SDU暑期集训排位题解
Posted onlymyheart
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDU暑期集训排位题解相关的知识,希望对你有一定的参考价值。
L - Olympiad Training
$FWT$。首先,观察到$n$很小,我们可以想办法求出每个子集的答案,但是$m$很大,直接枚举子集的方法肯定行不通。不妨考虑对每个$topic$单独考虑贡献,设当前考虑的是第$j$个$topic$,然后枚举最大值,设$a_ij$为最大值,其他的人我们只能选比它小的,设我们能选出的最大的集合为$mask$,显然,对于$mask$子集$s$,如果$s$包含第$i$个人,答案就需要加上$a_ij$,如果不包含,它的最大值就为其他值,我们不妨分两步完成这个操作,首先,对于$mask$的所有子集加上答案$a_ij$,然后,设$mask‘$为$mask$去掉$i$之后的集合,我们对$mask‘$的所有子集减去$a_ij$,到此为止,如果我们能快速完成给子集同时加上一个数这个操作,这个题就做完了,$and$运算的$FWT$支持此操作。
1 #include<iostream> 2 #include<cstdio> 3 #include<vector> 4 #include<algorithm> 5 const int N=22; 6 int n,q,m; 7 typedef long long ll; 8 ll f[1<<20],ans[22]; 9 typedef std::pair<int,int> P; 10 std::vector<P> g[10004]; 11 void FWT(ll *a,int n) 12 for(int i=1;i<n;i<<=1) 13 for(int p=i<<1,j=0;j<n;j+=p) 14 for(int k=0;k<i;k++) 15 a[j+k]+=a[i+j+k]; 16 17 int main() 18 int T; 19 scanf("%d",&T); 20 while(T--) 21 scanf("%d%d%d",&n,&m,&q); 22 for(int i=0;i<1<<n;i++) f[i]=0; 23 for(int i=0;i<m;i++) g[i].clear(); 24 for(int i=0;i<n;i++) 25 for(int j=0,x;j<m;j++) 26 scanf("%d",&x); 27 g[j].push_back(P(x,i)); 28 29 30 for(int i=0;i<m;i++) 31 std::sort(g[i].begin(),g[i].end()); 32 int mask=0; 33 for(P c:g[i]) 34 mask|=1<<c.second; 35 f[mask]+=c.first; 36 f[mask^(1<<c.second)]-=c.first; 37 38 39 FWT(f,1<<n); 40 for(int i=1;i<=n;i++) ans[i]=1e18; 41 for(int i=1;i<1<<n;i++) 42 int k=0; 43 for(int j=0;j<n;j++) if(i>>j&1) ++k; 44 ans[k]=std::min(ans[k],f[i]); 45 46 for(int k;q--;) 47 scanf("%d",&k); 48 printf("%lld\n",ans[k]); 49 50 51 return 0; 52
以上是关于SDU暑期集训排位题解的主要内容,如果未能解决你的问题,请参考以下文章