题目 | typewriter
AtCoder Beginner Contest 246
F - typewriter
https://atcoder.jp/contests/abc246/tasks/abc246_f
Time Limit: 2 sec / Memory Limit: 1024 MB
Score :
Problem Statement
We have a typewriter with
Let us use this keyboard to enter a string, as follows.
- First, choose an integer
. - Then, start with an empty string and only use the keys in the
-th row from the top to enter a string of length exactly .
How many strings of length
Constraints
and are integers. is a (not necessarily contiguous) non-empty subsequence ofabcdefghijklmnopqrstuvwxyz
.
Input
Input is given from Standard Input in the following format:
Output
Print the answer.
Sample Input 1
2 2
ab
ac
Sample Output 1
7
We can enter seven strings: aa
, ab
, ac
, ba
, bb
, ca
, cc
.
Sample Input 2
4 3
abcdefg
hijklmnop
qrstuv
wxyz
Sample Output 2
1352
Sample Input 3
5 1000000000
abc
acde
cefg
abcfh
dghi
Sample Output 3
346462871
Be sure to print the answer modulo
我的笔记
容斥原理
我们要求
用数学语言描述容斥原理如下:
(图片和公式来源:维基百科,使用 CC BY-NC-SA 4.0 许可)
题目转化
题目要求第
这所有情况加起来为
求种数
如果我们知道,第
如果我们知道,第
因此不需要知道具体有那几个字母,只需知道字母个数即可。
位运算的巧妙
官方题解位运算更巧妙,不过我看着不习惯,还是换成了数组。运行时长长了
这里只说一个我觉得挺好的用法,就是 36 行的 for (int i = 1; i < (1 << N); i++)
和 43 行的 if (i & (1 << j))
前者用二进制的方法,只用了一个 for 循环就完成了容斥定理 选
选择方法是 i & (1 << j)
便是这个目的
源码
#include <bits/stdc++.h>
#define MOD 998244353
using namespace std;
long long fast_pow(long long a, long long b)
{
a %= MOD;
long long ans = 1;
while (b)
{
if (b % 2)
{
ans = ans * a % MOD;
}
b /= 2;
a = a * a % MOD;
}
return ans;
}
int main()
{
int N, L;
cin >> N >> L;
bool row[18][26];
memset(row, false, sizeof(row));
for (int i = 0; i < N; i++)
{
string keys;
cin >> keys;
for (auto &key : keys)
row[i][key - 'a'] = true;
}
long long ans = 0;
for (int i = 1; i < (1 << N); i++)
{
bool these_rows[26];
memset(these_rows, true, sizeof(these_rows));
int selected_row_cnt = 0, selected_key_cnt = 0;
for (int j = 0; j < N; j++)
{
if (i & (1 << j))
{
selected_row_cnt++;
for (int k = 0; k < 26; k++)
{
these_rows[k] &= row[j][k];
}
}
}
for (int i = 0; i < 26; i++)
{
if (these_rows[i])
selected_key_cnt++;
}
if (selected_row_cnt % 2)
{
ans += fast_pow(selected_key_cnt, L);
ans %= MOD;
}
else
{
ans += MOD - fast_pow(selected_key_cnt, L);
ans %= MOD;
}
}
cout << ans << endl;
return 0;
}
本文采用 CC BY-SA 4.0 许可,本文 Markdown 源码:Haotian-BiJi