【TCO 2013 WildCard】SemiMultiple

来源:互联网 发布:网络覆盖解决方案 编辑:程序博客网 时间:2024/05/21 20:25

Description

定义一个非负数  是  长度下的  的半倍数,为  不是  的倍数,且  是  的倍数。
问有多少个  长度下的  的半倍数。

Difficulty

MainAlgorithm

容斥
DP

Complexity

Solution

比较难……
我们肯定是要对每个余数分别讨论的,可以用  的DP很轻松地把  以下的所有模  为 的数搞出来。
这样就能发现只有余数  或  时才有可能是半倍数的。
但是也有不合法的,当且仅当应该减去  的位都是0,应该加上  的位都是1。
对于每个模数都去DP这个不合法的是  的,显然不行。我们要继续挖掘性质。
我们发现,当  时,所有数都不合法。
当 是个偶数时,我们讨论第一位的取值。当第一位取  ,只要剩下的  位是  的倍数即可。当第一位取  ,只要剩下的  位是  的半倍数即可。
那么我们只需要解决  是个奇数的情况了。而且我们发现  在模奇数意义下在一个小环内!即实际上  存在循环节。
我们先将  的情况DP出来,我们可以直接利用这个DP的结果得到  的结果。需要做的只有将整个DP的答案左移即可。
实际上,当  时,只需要取出在  位处的DP值,并补上前  位的部分即可。
然后一个非常混乱的  的DP就能解决这个问题了。


我的做法稍有不同。

最后对于奇数部分,我们先DP出所有方案,为了减去不合法的,我们应当将DP反向倒退,由于此DP的特殊性,这一步相当于解一个方程,这个方程十分好解,于是就完成了。。


#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#define Rep(i, x, y) for (int i = x; i <= y; i ++)#define Dwn(i, x, y) for (int i = x; i >= y; i --)#define RepE(i, x) for(int i = pos[x]; i; i = g[i].nex)using namespace std;typedef long long LL;const int N = 2005, mod = 1000000007, p2 = (mod + 1) >> 1;LL p0, ans, f[N][N], h[N], g[N];int d[N], n, m; bool vis[N];class SemiMultiple {public:void Find(int x, int y) {while (x --) {memset (vis, 0, sizeof(vis));Rep(i, 0, m - 1) if (!vis[i]) {LL sum = 0;for (int j = i; !vis[j]; j = (j + y) % m) {(sum += h[j]) %= mod, vis[j] = 1;} sum = sum * p2 % mod;bool fl = 0; int j = i;do {if (fl) sum = (sum - h[j] + mod) % mod;fl ^= 1; j = (j + y) % m;} while (j != i);// h[m+i-y] = sum;j = i; do {h[j] = (h[j] - sum + mod) % mod; sum = h[j]; j = (j + y) % m;} while (j != i);}}}int count(int n1, int m1) {n = n1, m = m1;while (n && m % 2 == 0) m /= 2, p0 ++, n --;int r = 1; f[0][0] = 1;Rep(i, 1, n) {d[r] ++;Rep(j, 0, m - 1) f[i][j] = f[i - 1][j];Rep(j, 0, m - 1) (f[i][(j + r) % m] += f[i - 1][j]) %= mod;r = r * 2 % m;} // f[i][j] choose any of them    mod m == jans = p0 * f[n][0] % mod;Rep(i, 1, m - 1) if (d[i] || d[m - i]) {// int x = d[i];(ans += f[n][i]) %= mod;Rep(j, 0, m - 1) h[j] = f[n][j];Find(d[i], i), Find(d[m - i], m - i);Rep(t0, 1, d[m - i]) {Rep(j, 0, m - 1) g[(j + m - i) % m] = h[j];Rep(j, 0, m - 1) h[j] = g[j];}ans = (ans - h[i] + mod) % mod;}return ans;}};


0 0
原创粉丝点击