【BestCoder Round 65E】【网络流+讨论 奇偶分类思想】n个数形成若干至少3元素素数环的可行性检验 数可以为1

来源:互联网 发布:兰蔻臻白精华乳 知乎 编辑:程序博客网 时间:2024/05/18 05:10

ZYB's Prime

 
 Accepts: 5
 
 Submissions: 89
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 131072/131072 K (Java/Others)
问题描述
ZYB(ZJ-267)ZYB(ZJ267)NOIP AKNOIPAK又创造出了一道题:给出NN 个数,现在要求将它们分成KK 组(K \geq 1K1),每组数的个数都\geq 33,将每组中的数排成一个环,要求相邻的两个数加起来是个质数.ZYBZYB想要问你对于这NN个数,能不能将它们分组?
输入描述
第一行一个整数TT表示数据组数。接下来每组数据:  第一行一个正整数NN.  第二行NN个正整数AiAi,描述这NN个数.1 \leq T \leq 501T50,1 \leq N \leq 2001N200,1 \leq A_i \leq 2001Ai200,对6060%的数据N \leq 20N20.
输出描述
TT行每行输出YESYESNONO.
输入样例
273 4 8 9 1 1 131 2 3
输出样例
YESNO


#include<stdio.h>#include<iostream>#include<string.h>#include<string>#include<ctype.h>#include<math.h>#include<set>#include<map>#include<vector>#include<queue>#include<bitset>#include<algorithm>#include<time.h>using namespace std;void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}#define MS(x,y) memset(x,y,sizeof(x))#define MC(x,y) memcpy(x,y,sizeof(x))#define MP(x,y) make_pair(x,y)#define ls o<<1#define rs o<<1|1typedef long long LL;typedef unsigned long long UL;typedef unsigned int UI;template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}const int N=200+10,M=20400+10,Z=1e9+7,ms63=1061109567;int casenum,casei;bool e[400+10];//最大边数为(100*100+200)*2void prime(){int top=400;for(int i=2;i<=top;i++)if(e[i]==0){for(int j=i+i;j<=top;j+=i)e[j]=1;}}int n,id,ST,ED;int a[N],first[N];int w[M],c[M],cap[M],nxt[M];void ins(int x,int y,int cap_){id++;w[id]=y;cap[id]=cap_;nxt[id]=first[x];first[x]=id;id++;w[id]=x;cap[id]=0;nxt[id]=first[y];first[y]=id;}int d[N];bool bfs(){MS(d,-1);d[ST]=0;queue<int>q;q.push(ST);while(!q.empty()){int x=q.front();q.pop();for(int z=first[x];z;z=nxt[z])if(cap[z]){int y=w[z];if(d[y]==-1){d[y]=d[x]+1;if(y==ED)return 1;q.push(y);}}}return 0;}int dfs(int x,int all){if(x==ED)return all;int use=0;for(int z=first[x];z;z=nxt[z])if(cap[z]){int y=w[z];if(d[y]==d[x]+1){int tmp=dfs(y,min(cap[z],all-use));cap[z]-=tmp;cap[z^1]+=tmp;use+=tmp;if(use==all)break;}}if(use==0)d[x]=-1;return use;}int dinic(){int ans=0;while(bfs())ans+=dfs(ST,n*2);return ans;}bool vis[N];int b[N][N],sum;int p[N];int pp[N];bool check(){int one=0,odd=0,even=0;for(int i=1;i<=n;i++){if(a[i]==1)p[++one]=i;if(a[i]&1){++odd;ins(ST,i,2);for(int j=1;j<=n;j++)if(a[j]!=1&&!e[a[i]+a[j]])ins(i,j,1);//细节:我们不使得1向1连边。}else{++even;ins(i,ED,2);}}if(even>odd)return 0;if(even==odd)return dinic()==n;if(/*even<odd&&*/odd-even<=one)//这是一定会缩1的情况{int dec=odd-even;for(int z=first[p[one]];z;z=nxt[z])if(cap[z]==1)cap[z]=2;//把缩的点合并成一个special onefor(int i=1;i<=dec;++i)first[p[i]]=0;//把去除的点都delete掉if(dec==one&&one<3)return 0;//如果把1全部删掉,要求1的个数必须至少为3else return dinic()==even+even;}else return 0;}int main(){prime();scanf("%d",&casenum);for(casei=1;casei<=casenum;++casei){scanf("%d",&n);ST=0;ED=n+1;MS(first,0);id=1;for(int i=1;i<=n;i++)scanf("%d",&a[i]);puts(check()?"YES":"NO");}return 0;}/*【trick&&吐槽】这题好可惜啊!比赛的时候就差一种情况没有考虑到!就是1+x=奇数,恰好它们需要在一起的情况。这种情况的解法是,我们考虑把1【题意】给你n(1<=n<=200)个数,每个数的数值范围都在[1,200]。我们想要把这些数分为若干组。使得——1,每组内数的个数不超过3,2,每组的数形成一个环,环上两两相邻的数的和都是素数。【类型】网络流【分析】这道题是 CF290(Div2)E的升级版。不同的是,这道题的数值范围包括了1.如果不包括1,问题会怎么样?显然,素数不可能是2,只会是奇数。于是,相邻两个数必定是一奇一偶。于是,每个环中数的个数也必定为偶数个。(题目中也必须要使得奇数和偶数的个数都相同)然后,我们把所有奇数向与之之和为素数的偶数之间连一条流量为1的边超级源点向所有奇数连一条流量为2的边所有奇数向超级汇点连一条流量为2的边然后如果最大流==点数n,那么说明有解。这样建图,每个奇数必然会匹配到2个偶数,于是自然使得每个组中,数的个数都必然至少为4个,保证了做法天衣无缝。===============================================================问题回归,现在数可以为1了。会产生什么影响呢?如果只有1个1,是没有任何影响的。如果超过1个1,两个1之间是可以形成一个素数的,即,会出现奇数向奇数连边的情况。而且,其实对我们产生干扰的,也只有1向1连边这一种情况。(情况1)如果这些1不形成环,只是链关系的话,我们可以考虑移除1~n-1个1,设剩余数的个数为m,我们需要查看,是否剩下的数可以跑出流量为m的最大流。至于我么移除的1,随便和剩下的哪个1相邻即可。(也就是有一种——1个1可以拆出多个1的意味。)这个肯定不会把是YES的情况判定为NO。这种做法下,1的个数需要至少为2个。(情况2)然而,如果1的个数如果是大于等于3,我们是可以把所有的1都移除的。因为这些1可以自成一环。以上做法的思想是什么呢?就是因为发现1可以与自己相连。所以采取的一种——"如果1多了,以至于出现1和1连边的情况了,那么我们试着减少1的数量"的做法。(情况3)然而,这个量的减少,有时候会产生错误——因为1的减少,我们可能一个环中只剩下2个数了。如果有这么的一个情况出现,这种环的个数,也必然只有1个。否则2个环可以拼起来。于是,我们缩1,不能盲目缩,我们可以缩出special one。什么叫做special one呢?就是这个1,连向的sum=prime的偶数的边的流量,由1变成了2。这个解决了情况3出现的影响。也不会产生任何非法干扰。于是就可以AC掉这题啦!【时间复杂度&&优化】这题我会不断删点,不断做网络流。然而流量是不断减少的,于是我们每次都要重置边的流量。所以,我们可以使得一开始从流量最少的情况入手,不断加边。这样就不会重置边,可以有加速的奇效。然而,我们还发现,在经过我们的缩1操作处理之后。实际上,奇数的个数还是要和偶数个数保持相同。因为偶数个数是不变的。所以,事实上只需要对一个值跑网络流即可。啦啦啦啦啦~*/


0 0
原创粉丝点击