zoukankan      html  css  js  c++  java
  • [ARC080D] Prime Flip

    前言

    ARC080D

    题目

    洛谷

    AT

    讲解

    区间翻转考虑差分,差分后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;
    }
    
  • 相关阅读:
    poi 导出Excel
    【EasyUI】combotree和combobox模糊查询
    多线程和Socket套接字
    io流
    前端页面的语法 jquery javascript ajax
    spring+mybatis
    Exchanger 原理
    CountDownLatch、CyclicBarrier和 Semaphore
    sleep() 、join()、yield()有什么区别
    创建线程的方式及实现
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/14409351.html
Copyright © 2011-2022 走看看