码迷,mamicode.com
首页 > 其他好文 > 详细

SP2829 TLE (FWT)

时间:2020-02-11 00:17:26      阅读:70      评论:0      收藏:0      [点我收藏+]

标签:cstring   sum   html   case   tle   return   有关   getch   完整   

高维前缀和

众所周知, FWT可以轻松的算出高维前缀和

本题题解:

考虑状压\(dp\)(题目都说了\(2^M\)那就状压了)因为\(\%c[i]\)\(\&a[i-1]\)这两个操作都和具体的数值有关

\(F[i][j]\)表示枚举到\(i\), 第\(i\)个数填\(j\)有多少种方案
\[ F[i][j] = \begin{cases} 0~~~~~~~~~~~ j~\%~c[i] ==0\\\\\displaystyle \sum_{k\&j=0} F[i-1][j]\end{cases} \]
这样显然是不行的, 需要一点优化

转移时发现每一个合法的k都是\(j \bigotimes (2^M-1)\)的子集, 如果能记个子集前缀和那就再好不过了, FWT可以帮我们完成这件事, 一遍FWT_or算出子集和, 给出一份易于背诵的代码吧 戳这里

完整代码

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
const int P = 1000000000;
template <typename T>
void read(T &x) {
    x = 0; bool f = 0;
    char c = getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
    for (;isdigit(c);c=getchar()) x=x*10+(c^48);
    if (f) x=-x;
}

ll ans = 0, n, m;
void FWT_or(ll *f) {
    for (int i = 1, p = 2; i < m; i <<= 1, p <<= 1) 
        for (int j = 0; j < m; j += p) 
            for (int k = 0; k < i; k++) 
                (f[i+j+k] += f[j+k]) %= P;
}

const int N = 55;
ll f[N][(1<<15) + 5], a[N];

int main() {
    int T; read(T);
    while (T--) {
        memset(f, 0, sizeof(f));
        read(n), read(m); m = 1 << m;
        for (int i = 1; i <= n; i++) read(a[i]);
        for (int i = 1; i < m; i++) 
            if (i % a[1]) f[1][i] = 1;
        FWT_or(f[1]);
        for (int i = 2; i <= n; i++) {
            for (int j = 1; j < m; j++) {
                if (j % a[i] == 0) continue;
                f[i][j] += f[i-1][(m-1)^j];
            }
            FWT_or(f[i]);
        }
        cout << f[n][m-1] << endl;
    }
    return 0;
}

SP2829 TLE (FWT)

标签:cstring   sum   html   case   tle   return   有关   getch   完整   

原文地址:https://www.cnblogs.com/Hs-black/p/12293480.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!