@xiaoziyao
2020-11-20T08:40:59.000000Z
字数 2353
阅读 1493
解题报告
AT2689 [ARC080D] Prime Flip解题报告:
神仙题,调了一下午/kk。
首先有一个套路的想法,设为第个硬币是否与第个硬币不同,这样我们的区间反转操作会变为和反转,我们的目标会变为让所有的变为。
然后,我们可以很简单的求出来所有为的位置,然后题目便转化为了如何用最少的操作让这些全部为。
考虑抵消和()的条件:
对于知道了上面的结论后,我们有一个贪心的想法:尽量多的消除为奇素数的情况,然后尽量多的消除为偶数的情况,其他的进行第三种情况,这个贪心策略显然是正确的。
考虑把所有差为奇素数的数连边,这样这个新图一定是一个二分图,原因是奇数只会和偶数连边,而且很显然这个新图的最大匹配为第一种情况的最多情况。
消除完所有能进行操作的情况后,剩下来可以进行操作的两个数一定奇偶性相同,这样我们分奇偶消除一下就好了。
最后有可能剩下两个奇偶性不相同的数(原因是为偶数,如果剩下两个奇偶性相同的一定可以继续消除,所以要么一个不剩,要么剩两个奇偶性不同的数),这一对数我们运用操作消除就好了。
#include<stdio.h>#include<vector>#include<string.h>using namespace std;const int maxn=205,maxk=10000005,maxm=maxn*maxn;int n,stp,cnt,fir,e,ans,vs;int start[maxn],to[maxm],then[maxm],match[maxn],vis[maxn],a[maxk],p[maxk],flg[maxn],x[maxn],tot[2];vector<int>v;inline int abs(int x){return x<0? -x:x;}inline void add(int x,int y){then[++e]=start[x],start[x]=e,to[e]=y;}int Hungary(int x){for(int i=start[x];i;i=then[i]){int y=to[i];if(vis[y]==stp)continue;vis[y]=stp;if(match[y]==-1||Hungary(match[y])){match[y]=x;return 1;}}return 0;}int main(){memset(match,-1,sizeof(match));for(int i=2;i<maxk;i++){if(p[i]==0)a[++cnt]=i;for(int j=1;j<=cnt;j++){if(i*a[j]>=maxk)break;p[i*a[j]]=1;if(i%a[j]==0)break;}}p[0]=p[1]=p[2]=1;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&x[i]);v.push_back(x[1]-1);for(int i=1;i<n;i++)if(x[i]+1<x[i+1])v.push_back(x[i]),v.push_back(x[i+1]-1);v.push_back(x[n]),vs=v.size();for(int i=0;i<vs;i++)for(int j=0;j<vs;j++)if(v[i]%2==0&&p[abs(v[i]-v[j])]==0)add(i,j);for(int i=0;i<vs;i++){if(v[i]%2==0)stp++,fir+=Hungary(i);tot[v[i]%2]++;}ans=fir+((tot[1]-fir)/2+(tot[0]-fir)/2)*2;if((tot[0]-fir)%2==1)ans+=3;printf("%d\n",ans);return 0;}
