SPOJ2829 TLE-Time Limit Exceeded

题目链接——SPOJ
题目链接——洛谷

problem

给出n,m和一个长度为n的数列c。求有多少个数列a满足以下条件:

  • \(1\le a_i < 2^m\)
  • \(a_i\&a_{i-1}=0\)
  • \(c_i\nmid a_i\)

答案读对\(1000000000\)取模。

solution

\(f[t][i]\)表示长度为t且以i结尾的满足条件的数列的数量。\(f[t][i]=\sum\limits_{j,j\&i=0}f[t-1][j]\)

观察\(j\&i=0\)这个限制,其实等价于\(i\&(\sim j)=i\)。所以每次处理完之后,将答案的下标与自己的补集交换,然后就成了枚举超集。用\(FMT\)优化即可。复杂度\(\Theta(nm2^m)\)

这样处理完了前两个限制,对于第三个限制,每次处理完之后将下标\(c_i\)倍数的答案变为0即可。

code

/*
* @Author: wxyww
* @Date:   2019-12-15 09:58:26
* @Last Modified time: 2019-12-15 10:11:19
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef long long ll;
const int N = 1 << 20,mod = 1000000000;
ll read() {
    ll x = 0,f = 1;char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1; c = getchar();
    }
    while(c >= '0' && c <= '9') {
        x = x * 10 + c - '0'; c = getchar();
    }
    return x * f;
}
int f[N],a[N];
int main() {
    int T = read();
    while(T--) {
        int n = read(),m = read();
        int LIM = (1 << m) - 1;
        memset(f,0,sizeof(f));
        f[0] = 1;
        for(int i = 1;i <= n;++i) a[i] = read();

        for(int i = 1;i <= n;++i) {

            for(int j = 0;j <= LIM;j += 2) swap(f[j],f[j ^ LIM]);

            for(int j = 0;j < m;++j) {
                for(int k = 0;k <= LIM;++k) {
                    if(!(k >> j & 1)) f[k] += f[k | (1 << j)],f[k] %= mod;
                }
            }
            for(int j = 0;j <= LIM;j += a[i]) f[j] = 0;
        }

        ll ans = 0;
        for(int i = 0;i <= LIM;++i) ans += f[i],ans %= mod;

        printf("%lld\n",ans);   

    }

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wxyww/p/SPOJ2829.html