前言
ARC080D
题目
讲解
区间翻转考虑差分,差分后1的数量一定为偶数。
然后考虑将差分后的1分为奇数和偶数,组成天然的二分图。
此时我们有三种操作:
1.奇质数,代价为(1)。
2.偶数,代价为(2),原理为哥德巴赫猜想。(特例:2=5-3,4=7-3)
3.奇合数,代价为(3),原理为奇质数3+操作2。
考虑奇偶相减为奇数,所以我们可以对操作1跑二分图匹配,剩下的尽量用操作2,实在不行用操作3。
tip:判断奇质数不用线性筛会快很多。
代码
大部分是dinic的板子
int head[MAXN],tot = 1;
struct node
{
int v,w,nxt;
}e[MAXN * MAXN];
void Add_Edge(int x,int y,int z)
{
e[++tot].v = y;
e[tot].w = z;
e[tot].nxt = head[x];
head[x] = tot;
}
void Add_Double_Edge(int x,int y,int z)
{
Add_Edge(x,y,z);
Add_Edge(y,x,0);
}
int dis[MAXN],q[MAXN];
bool bfs()
{
for(int i = 1;i <= N;++ i) dis[i] = -1;
int l,r; dis[q[l = r = 1] = S] = 0;
while(l <= r)
{
int p = q[l++];
for(int i = head[p]; i ;i = e[i].nxt)
if(e[i].w > 0 && dis[e[i].v] == -1)
dis[e[i].v] = dis[p] + 1,q[++r] = e[i].v;
}
return dis[T] != -1;
}
int cur[MAXN];
int dfs(int x,int flow)
{
if(x == T) return flow;
int ret = 0;
for(int &i = cur[x]; i ;i = e[i].nxt)
if(e[i].w > 0 && dis[x] + 1 == dis[e[i].v])
{
int dz = dfs(e[i].v,Min(e[i].w,flow-ret));
e[i].w -= dz; e[i^1].w += dz;
if((ret += dz) == flow) break;
}
if(!ret) dis[x] = -1;
return ret;
}
int dinic()
{
int ret = 0;
while(bfs())
{
for(int i = 1;i <= N;++ i) cur[i] = head[i];
ret += dfs(S,INF);
}
return ret;
}
int l[MAXN],r[MAXN],ltot,rtot;
void Add(int x)
{
if(x & 1) l[++ltot] = x;
else r[++rtot] = x;
}
bool check(int x)
{
if(x <= 2) return 0;
if(!(x & 1)) return 0;
for(int i = 3;i * i <= x;++ i)
if(x % i == 0) return 0;
return 1;
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = Read();
for(int i = 1;i <= n;++ i) a[i] = Read();
Add(a[1]);
for(int i = 2;i <= n;++ i)
if(a[i] > a[i-1]+1)
{
Add(a[i-1]+1);
Add(a[i]);
}
Add(a[n]+1);
S = ltot + rtot + 1; N = T = S + 1;
for(int i = 1;i <= ltot;++ i) Add_Double_Edge(S,i,1);
for(int i = 1;i <= rtot;++ i) Add_Double_Edge(i+ltot,T,1);
for(int i = 1;i <= ltot;++ i)
for(int j = 1;j <= rtot;++ j)
if(check(Abs(l[i]-r[j])))
Add_Double_Edge(i,j+ltot,1);
int sum = dinic();
Put(sum + (ltot - sum) / 2 * 2 + (rtot - sum) / 2 * 2 + ((ltot - sum) & 1) * 3);//ltot与rtot奇偶性一定相同,所以只需要用ltot-sum判断
return 0;
}