本文主要是介绍第九届中国大学生程序设计竞赛(秦皇岛)-(CCPC2023-Qinhuangdao F - 质数之谜(DP),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
题意
给定一个序列,修改最少数量的元素使得任意i属于[1,n-1],q[i]+q[i+1]都为质数,输出最小修改次数
思路
首先手玩的过程中可以发现,
如果因为前面一个数字和自己相加不是质数然后我把自己变成了奇数,那么如果我后面一个数字是偶数
可以发现自己肯定能找到另一个奇数使得和前面相加互质并且和后面相加也互质
举个例子:假设为2 8 10,我此时是8,我发现2+8不是质数把自己改为5,但是5+10不是质数,但是无论如何我都可以找到一个数字(因为这个数字没有范围限制)x,使得x+2和x+10都是质数,这个样例中取x=3即可
由于前面的修改会影响后面的修改,所以考虑用线性DP来写
然后由发现的结论可以知道,假设前面的一个数字已经被修改过并且改为奇数,那么如果此时位置的数为偶数,那么前面一个数字一定能再找到一个奇数(还是相当于只修改一次)使得这个偶数和奇数互质
但是由于1(奇数)+1(奇数)奇偶性相同但是也满足结论,所以变1这个情况要特判
那么dp有4个状态,0:不变 1:变偶数 2:变奇数(非1) 3:变1
只要考虑每个状态可以由什么状态转移过来就可以解决这个问题
f[i-1][0]:如果原数组前后两个数互质时候(!st[q[i-1]+q[i])
f[i-1][1]:如果q[i]为奇数,并且前一个变成了偶数也就是f[i-1][1]
f[i-1][2]:如果q[i]为偶数,并且前一个变成了奇数也就是f[i-1][2]
f[i-1][3]:如果q[i]+1为质数
----->可以转移给f[i][0]状态
f[i-1][0]:q[i-1]为奇数的时候
f[i-1][1]:如论如何都不能转移
f[i-1][2]:一定可以转移
f[i-1][3]:一定可以转移
----->可以转移给f[i][1]状态
f[i-1][0]:q[i-1]为偶数的时候
f[i-1][1]:一定可以转移
f[i-1][2]:如论如何都不能转移
f[i-1][3]:如论如何都不能转移
----->可以转移给f[i][2]状态
f[i-1][0]:q[i-1]+1为奇数的时候
f[i-1][1]:一定可以转移
f[i-1][2]:如论如何都不能转移
f[i-1][3]:q[i-1]不等于1的时候(因为等于就不是变成1的情况了)可以转移
----->可以转移给f[i][3]状态
*/
代码实现
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define pp pop_back()
#define int long long
#define laile cout<<"laile"<<endl
#define lowbit(x) ((x)&(-x))
#define double long double
#define sf(x) scanf("%lld",&x)
#define sff(x,y) scanf("%lld %lld",&x,&y)
#define sd(x) scanf("%Lf",&x)
#define sdd(x,y) scanf("%Lf %Lf",&x,&y)
#define _for(i,n) for(int i=0;i<(n);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
#define _pre(i,a,b) for(int i=(a);i>=(b);--i)
#define all(x) (x).begin(), (x).end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef unsigned long long ULL;
typedef pair<int,int>PII;
const int N=1e6+10,INF=4e18;
int n,m;
int q[N];
int f[N][5];
int prime[N],cnt;
bool st[N];
//0不变 1变偶 2变奇 3变1
void init()
{for(int i=2;i<=200000;i++){if(!st[i])prime[cnt++]=i;for(int j=0;prime[j]*i<=200000;j++){st[prime[j]*i]=true;if(i%prime[j]==0)break;}}return;
}
void solve()
{cin>>n;_rep(i,1,n)cin>>q[i];memset(f,0x3f,sizeof(f));f[1][0]=0;f[1][1]=f[1][2]=f[1][3]=1;_rep(i,2,n){//0if(!st[q[i]+q[i-1]])f[i][0]=min(f[i][0],f[i-1][0]);if(q[i]%2)f[i][0]=min(f[i][0],f[i-1][1]);else f[i][0]=min(f[i][0],f[i-1][2]);if(!st[q[i]+1])f[i][0]=min(f[i][0],f[i-1][3]);//1,2if(q[i-1]%2)f[i][1]=min(f[i][1],f[i-1][0]+1);else f[i][2]=min(f[i][2],f[i-1][0]+1);f[i][1]=min(f[i][1],f[i-1][2]+1);f[i][1]=min(f[i][1],f[i-1][3]+1);f[i][2]=min(f[i][2],f[i-1][1]+1);//3if(!st[q[i-1]+1]&&q[i]!=1)f[i][3]=min(f[i][3],f[i-1][0]+1);f[i][3]=min(f[i][3],f[i-1][1]+1);if(q[i-1]!=1)f[i][3]=min(f[i][3],f[i-1][3]+1);}int res=INF;
//测试
// for(int i=1;i<=n;i++)
// {
// int now=INF;
// for(int j=0;j<=3;j++)
// {
// if(f[i][j]!=0x3f3f3f3f3f3f3f3f)
// cout<<f[i][j]<<" ";
// else cout<<"- ";
// }
// cout<<endl;
// }_rep(i,0,3)res=min(res,f[n][i]);cout<<res<<"\n";return ;
}
signed main()
{IOS;int T=1;init();
// cin>>T;while(T--)solve();return 0;
}
这篇关于第九届中国大学生程序设计竞赛(秦皇岛)-(CCPC2023-Qinhuangdao F - 质数之谜(DP)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!