[关闭]
@xiaoziyao 2020-11-20T08:40:59.000000Z 字数 2353 阅读 917

AT2689 [ARC080D] Prime Flip解题报告

解题报告


AT2689 [ARC080D] Prime Flip解题报告:

更好的阅读体验

题意

分析

神仙题,调了一下午/kk。

首先有一个套路的想法,设个硬币是否与第个硬币不同,这样我们的区间反转操作会变为反转,我们的目标会变为让所有的变为

然后,我们可以很简单的求出来所有的位置,然后题目便转化为了如何用最少的操作让这些全部为

考虑抵消)的条件:

对于知道了上面的结论后,我们有一个贪心的想法:尽量多的消除为奇素数的情况,然后尽量多的消除为偶数的情况,其他的进行第三种情况,这个贪心策略显然是正确的。

考虑把所有差为奇素数的数连边,这样这个新图一定是一个二分图,原因是奇数只会和偶数连边,而且很显然这个新图的最大匹配为第一种情况的最多情况。

消除完所有能进行操作的情况后,剩下来可以进行操作的两个数一定奇偶性相同,这样我们分奇偶消除一下就好了。

最后有可能剩下两个奇偶性不相同的数(原因是为偶数,如果剩下两个奇偶性相同的一定可以继续消除,所以要么一个不剩,要么剩两个奇偶性不同的数),这一对数我们运用操作消除就好了。

代码

  1. #include<stdio.h>
  2. #include<vector>
  3. #include<string.h>
  4. using namespace std;
  5. const int maxn=205,maxk=10000005,maxm=maxn*maxn;
  6. int n,stp,cnt,fir,e,ans,vs;
  7. int start[maxn],to[maxm],then[maxm],match[maxn],vis[maxn],a[maxk],p[maxk],flg[maxn],x[maxn],tot[2];
  8. vector<int>v;
  9. inline int abs(int x){
  10. return x<0? -x:x;
  11. }
  12. inline void add(int x,int y){
  13. then[++e]=start[x],start[x]=e,to[e]=y;
  14. }
  15. int Hungary(int x){
  16. for(int i=start[x];i;i=then[i]){
  17. int y=to[i];
  18. if(vis[y]==stp)
  19. continue;
  20. vis[y]=stp;
  21. if(match[y]==-1||Hungary(match[y])){
  22. match[y]=x;
  23. return 1;
  24. }
  25. }
  26. return 0;
  27. }
  28. int main(){
  29. memset(match,-1,sizeof(match));
  30. for(int i=2;i<maxk;i++){
  31. if(p[i]==0)
  32. a[++cnt]=i;
  33. for(int j=1;j<=cnt;j++){
  34. if(i*a[j]>=maxk)
  35. break;
  36. p[i*a[j]]=1;
  37. if(i%a[j]==0)
  38. break;
  39. }
  40. }
  41. p[0]=p[1]=p[2]=1;
  42. scanf("%d",&n);
  43. for(int i=1;i<=n;i++)
  44. scanf("%d",&x[i]);
  45. v.push_back(x[1]-1);
  46. for(int i=1;i<n;i++)
  47. if(x[i]+1<x[i+1])
  48. v.push_back(x[i]),v.push_back(x[i+1]-1);
  49. v.push_back(x[n]),vs=v.size();
  50. for(int i=0;i<vs;i++)
  51. for(int j=0;j<vs;j++)
  52. if(v[i]%2==0&&p[abs(v[i]-v[j])]==0)
  53. add(i,j);
  54. for(int i=0;i<vs;i++){
  55. if(v[i]%2==0)
  56. stp++,fir+=Hungary(i);
  57. tot[v[i]%2]++;
  58. }
  59. ans=fir+((tot[1]-fir)/2+(tot[0]-fir)/2)*2;
  60. if((tot[0]-fir)%2==1)
  61. ans+=3;
  62. printf("%d\n",ans);
  63. return 0;
  64. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注