标签:lse span eof += from include 奇数 rom sizeof
题目描述
There are infinitely many cards, numbered 1, 2, 3, … Initially, Cards x1, x2, …, xN are face up, and the others are face down.
Snuke can perform the following operation repeatedly:
Select a prime p greater than or equal to 3. Then, select p consecutive cards and flip all of them.
Snuke‘s objective is to have all the cards face down. Find the minimum number of operations required to achieve the objective.
Constraints
1≤N≤100
1≤x1<x2<…<xN≤107
输入
Input is given from Standard Input in the following format:
N
x1 x2 … xN
输出
Print the minimum number of operations required to achieve the objective.
样例输入
2
4 5
样例输出
2
提示
Below is one way to achieve the objective in two operations:
Select p=5 and flip Cards 1, 2, 3, 4 and 5.
Select p=3 and flip Cards 1, 2 and 3.
这题难度感觉很大。
首先要把问题抽象。我们设如果第i张牌如果与第i-1张牌面向不同,ai=1,否则为0.特别的,a0=0。这样有什么好处呢。
这样我们动形如1000001的序列时,翻动100000。会得到什么效果?首先第一个1会变成0(与前一个变为同向),而其他的0由于与其前一位同时反转,仍旧是0,而后面的1,会变成0.这样就变成了两点操作。
则最终目标变为:求最小操作数,使序列全为0.
考虑三种情况
A.|i-j|为素数:操作一次
B.|i-j|为偶数,哥德巴赫猜想,分解成两个素数,操作两次。
C.|i-j|为奇合数。分解成偶数减去奇素数,操作三次。
我们把位置为奇数的点,位置为偶数的点分为两组,显然要操作1最多。
则想到对位置之差为素数的两点连边,跑二分图。
匈牙利即可。
注意匈牙利时,不能为以0为点,不然会有问题。因为这个wa了好多发
#include<bits/stdc++.h>
#define maxn 10000005
#define maxv 205
using namespace std;
int prime[maxn/2];
bool vis[maxn];
int inde=0;
void primejudge(int n)//预处理素数筛
{
vis[1]=true;
int i,j;
for(i=2;i<=n;i++)
{
if(!vis[i])
{
prime[inde++]=i;
}
for(j=0;j<inde&&prime[j]*i<=n;j++)
{
vis[i*prime[j]]=true;
if(i%prime[j]==0) break;
}
}
vis[2]=true;
}
int cnt1,cnt2;
bool used[maxv];
int bel[maxv];
bool v[maxn];
int s[maxn];
int mp1[maxv];
int mp2[maxv];
bool match[maxv][maxv];
bool findd(int x)//匈牙利算法跑二分图
{ int i;
for(i=1;i<=cnt2;i++)
{
if(match[x][i]&&used[i]==false)
{
used[i]=true;
if(!bel[i]||findd(bel[i]))
{
bel[i]=x;
return true;
}
}
}
return false;
}
int main()
{
int n,i,u,cnt=0;
primejudge(10000003);
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&u);
v[u]=true;//存初始为翻开的点
}
for(i=1;i<=maxn-2;i++)
{
if(v[i]!=v[i-1])
{
s[cnt++]=i;//把为权为1的点的位置记录下来
}
}
for(i=0;i<cnt;i++)
{
if(s[i]&1)
{
mp1[++cnt1]=s[i];//奇数为一组
}
else
{
mp2[++cnt2]=s[i];//偶数为一组
}
}
for(i=1;i<=cnt1;i++)
{
for(int j=1;j<=cnt2;j++)
{
if(!vis[abs(mp1[i]-mp2[j])])
{
match[i][j]=true;//如果是素数,则在二分图中建边
}
}
}
int sum=0;
for(i=1;i<=cnt1;i++)//跑二分图
{
memset(used,false,sizeof(used));
if(findd(i)) sum++;
}
int ans=sum;
cnt1-=sum;//剩下没法匹配为素数的的肯定是cnt1-sum
cnt2-=sum;
ans+=cnt1/2*2;//剩下的内部匹配
ans+=cnt2/2*2;
ans+=cnt1%2*3;//余数肯定是与另一组的单独匹配
cout<<ans<<endl;
return 0;
}
Prime Flip
标签:lse span eof += from include 奇数 rom sizeof
原文地址:https://www.cnblogs.com/zyf3855923/p/9363240.html