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; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮