codeforces 788C The Great Mixing( BFS / dp+bitset优化 )

来源:互联网 发布:fedora 24 php 编辑:程序博客网 时间:2024/05/20 13:04
题意:n(1e3),k(1e6),a1~ak(1e3)。选取最少的ai(可以重复)t个,使得sum(ai)/t/1000==n/1000成立。
题解:
k(1e6),a1~ak(1e3) --> 数只有1e3个。
sum(ai)/t/1000==n/1000 --> sum(ai)==t*n --> sum(ai-n)==0
t<=2000:在有解的情况下,最少存在一个解为:选取ai,aj,ai<n,aj>n,t=abs(ai)+abs(aj)

解法一:BFS
如果存在一组解b1+b2+...+bt==0,那么我们可以改变数组元素的位置使得所有前缀和范围在[-1000,1000]。
那么我们可以以0为起点进行BFS,直到又回到0。

解法二:dp+bitset
考虑朴素的dp写法,dp[i][j]表示选取了i个元素能否到达状态j。伪代码如下:
for(int i=1;i<=2000;++i) {//枚举次数,至多2000次for(int j=0;j<=2000;++j) {//状态统一加1000变成正数for(int x=1;x<=m;++x) {if(0<=j-a[x]&&j-a[x]<=2000) d[i][j] |= d[i-1][j-a[x]];}}}

这样做的复杂度是n3,考虑到dp的状态只有01两种,我们可以用bitset优化。把第二层循环压成bitset,复杂度变成n3/64。
bitset内部实现:
内部维护了一个long数组,初始只有一个long,所以BitSet最小的size是64,当随着存储的元素越来越多,BitSet内部会动态扩充,最终内部是由N个long来存储,这些针对操作都是透明的。

#include<cstdio>#include<map>#include<cstdlib>#include<queue>using namespace std;#define mp make_pair#define fi first#define se secondconst int N=2020;map<int,bool> vis,vi;int a[N];int main() {int x,m;while(~scanf("%d%d",&x,&m)) {///initvis.clear();vi.clear();///readint n=0;for(int i=1;i<=m;++i) {int t;scanf("%d",&t);t-=x;if(!vis[t]) a[++n]=t;vis[t]=1;}///if(x==0) {if(vis[0]) puts("1");else puts("-1");continue;}///int cnt0=0,cnt1=0;for(int i=1;i<=n;++i) {if(a[i]>0) ++cnt0;if(a[i]<0) ++cnt1;}if(cnt0==n||cnt1==n) {puts("-1");continue;}///solvequeue<pair<int,int> > q;q.push(mp(0,0));bool flag=1;int ans;for(;flag;) {pair<int,int> now=q.front();q.pop();for(int i=1;i<=n;++i) {if(now.fi+a[i]==0) {flag=0;ans=now.se+1;break;}int nxt=now.fi+a[i];if(abs(nxt)<=1000&&!vi[nxt]) {q.push(mp(nxt,now.se+1));vi[nxt]=1;}}}///printprintf("%d\n",ans);}return 0;}

#include<cstdio>#include<map>#include<bitset>using namespace std;const int N=1007;map<int,bool> vis;bitset<N*2> dp[2];int a[N];int main() {int x,m;while(~scanf("%d%d",&x,&m)) {///initvis.clear();///readint n=0;for(int i=1;i<=m;++i) {int t;scanf("%d",&t);if(!vis[t]) a[++n]=t;vis[t]=1;}///solveint now=0,ans=-1;dp[now].reset();dp[now][1000]=1;for(int i=1;i<=2000&&ans==-1;++i) {now=1-now;dp[now].reset();for(int j=1;j<=n;++j) {dp[now] |= (dp[1-now]<<a[j])>>x;if(dp[now][1000]) {ans=i;break;}}}///printprintf("%d\n",ans);}return 0;}


0 0
原创粉丝点击