zoukankan      html  css  js  c++  java
  • SP2829 TLE (FWT)

    高维前缀和

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

    本题题解:

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

    (F[i][j])表示枚举到(i), 第(i)个数填(j)有多少种方案

    [F[i][j] = egin{cases} 0~~~~~~~~~~~ j~\%~c[i] ==0\\displaystyle sum_{k&j=0} F[i-1][j]end{cases} ]

    这样显然是不行的, 需要一点优化

    转移时发现每一个合法的k都是(j igotimes (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;
    }
    
  • 相关阅读:
    Linux之权限
    Linux基础和文件操作
    linux之用户、用户组、用户提权
    linux之Vim使用
    java面向对象
    eclipse首选项常用设置
    eclipse中添加项目运行程序
    eclipse的基本配置
    eclipse安装
    Jemter压力测试核心流程
  • 原文地址:https://www.cnblogs.com/Hs-black/p/12293480.html
Copyright © 2011-2022 走看看