返回顶部

Codeforces Round #502 (in memory of Leopoldo Taravilse, Div. 1 + Div. 2) D. The Wu (状压,预处理)

  • 题意:有一长度均相同的\(01\)串集合,每次询问给你一个同长度的\(01\)串,去和集合中的每个\(01\)串匹配,若位置\(i\)的元素相同,则贡献加\(w_i\),输出集合中有多少串匹配完后贡献不大于\(k\)

  • 题解:集合中元素很少,最多\(12\)个。先用桶标记集合中的串,然后\(O((1<<n)^2)\)预处理所有情况,\(i\)表示所有可能询问的情况,\(j\)表示集合中的串,这样就可以预处理所有长度为\(n\)\(01\)串的情况,然后询问的时候\(O(k)\)即可。

  • 代码

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
     
    int n,m,q;
    int w[N];
    string s[N];
    int res[5000][200];
    int mp[5000];
     
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    	cin>>n>>m>>q;
    	rep(i,0,n-1) cin>>w[i];
    	for(int i=1;i<=m;++i){
    		cin>>s[i];
    		int sum=0;
    		for(int j=0;j<n;++j){
    			if(s[i][j]=='1') sum+=(1<<j);
    		}
    		mp[sum]++;
    	}
    	
    	// pre
    	for(int i=0;i<(1<<n);++i){ //all situations
    		for(int j=0;j<(1<<n);++j){ //Wu
    			if(!mp[j]) continue;
    			int sum=0;
    			for(int k=0;k<n;++k){
    				if((i&(1<<k))==(j&(1<<k))){
    					sum+=w[k];
    					if(sum>100) break;
    				}
    			}
    			if(sum<=100) res[i][sum]+=mp[j];
    			//cout<<res[i][sum]<<'\n';
    		}
    	}
     
    	while(q--){
    		string t;
    		int k;
    		cin>>t>>k;
    		int sum=0;
    		int ans=0;
    		for(int i=0;i<n;++i){
    			if(t[i]=='1'){
    				sum+=(1<<i);
    			}
    		}
    		for(int i=0;i<=k;++i){
    			ans+=res[sum][i];
    		}
    		cout<<ans<<'\n';
    	}
     
        return 0;
    }
    
posted @ 2021-06-04 21:33  Rayotaku  阅读(43)  评论(0编辑  收藏  举报