考场想法
- 筛质数
- n 2 n^2 n2连边:加起来是质数的连边
- 求最大独立集,转二分图:左部右部都是原先节点
ans=(n*2-maxmatch)/2
以下是一堆对这道题没用的废话
- 求最大独立集:
建反图
所求为一个点集,使得其中所有点都能两两到达(团,但是NP完全问题不会)- 其实直接加起来不是质数的两个数连边就不必建反图了
(为什么还要绕一下逻辑呢)废话结束
Θ
(
n
2
log
n
)
\Theta(n^2\log n)
Θ(n2logn),二分需要一个
log
\log
log
跑不过去???
滚!质数没那么多qwq
不过二分图的
O
(
n
m
)
O(nm)
O(nm)让我感到有些不妙
其实不用担心:质数少,二分图稀疏
以上考场上想法
70pts(WA1T2)
考虑继续优化
发现可以优化左部右部:
一边奇数,一边偶数,奇偶之和得到可能的质数
ans=n-maxmatch
再考虑1+1=2
的情况,显然两个1是不相容的,取一个就行了
考虑采用更有效的筛法:(不是时间有效,是查询有效)
也就是埃筛,接近
O
(
n
)
O(n)
O(n)的复杂度很优秀了
而且调用方便,
O
(
1
)
O(1)
O(1)查询
用这种方法只T一个点,吸点氧后全A
看来我的常数还是比机房里人都小好多啊✌️
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define debug puts("qwq")
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=3e3+5,M=2e5+5;
int n,m,A[N],B[N],data[N];
bool isprime[M];
vector<int>G[N];
int mat[N],tim,dfn[N];
void Init(){
int cnt=in;
for(int i=1;i<=cnt;++i) data[i]=in;
bool flag=true;
for(int i=1;i<=cnt;++i){
if(data[i]==1&&flag){
A[++n]=data[i];
flag=false;
}
if(data[i]>1&&(data[i]&1==1)) A[++n]=data[i];
if((data[i]&1)==0) B[++m]=data[i];
}
memset(isprime,true,sizeof isprime);
isprime[1]=isprime[0]=false;
for(int i=2;i<M;++i){
if(!isprime[i]) continue;
for(int j=i+i;j<M;j+=i) isprime[j]=false;
}
return;
}
bool DFS(int u){
for(int e=0;e<G[u].size();++e){
int v=G[u][e];
if(dfn[v]!=tim){
dfn[v]=tim;
if(!mat[v]||DFS(mat[v])){
mat[v]=u;
return true;
}
}
}
return false;
}
int main(){
Init();
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j){
if(isprime[A[i]+B[j]]) G[i].push_back(j);
}
int ans=0;
for(int i=1;i<=n;++i){
++tim;
ans+=DFS(i);
}
printf("%d\n",n+m-ans);
return 0;
}
考场版,当然这个被魔改了一点
也挺好的
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define debug puts("qwq")
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=1e4+5,M=3e5+5;
int n,p[M],sz,vis[M],a[N];
int b[N];
int dfn[N],tim,mat[N],ans;
vector<int>G[N];
void get_prime(int up){
for(int i=2;i<=up;++i){
if(vis[i]==0) {vis[i]=i;p[++sz]=i;}
for(int j=1;j<=sz;++j){
if(p[j]>vis[i]||p[j]>up/i) break;
vis[i*p[j]]=p[j];
}
}
return;
}
bool DFS(int u){
for(int e=0;e<G[u].size();++e){
int v=G[u][e];
if(dfn[v]!=tim){
dfn[v]=tim;
if(!mat[v]||DFS(mat[v])){
mat[v]=u;
return true;
}
}
}
return false;
}
int main(){
// freopen("prime.in","r",stdin);
// freopen("prime.out","w",stdout);
n=in;
get_prime(M);
for(int i=1;i<=n;++i) b[i]=in;
bool flag=true;int cnt=0;
for(int i=1;i<=n;++i){
if(b[i]!=1||(b[i]==1&&flag))
a[++cnt]=b[i];
if(b[i]==1) flag=false;
}n=cnt;
for(int i=1;i<=n;++i)
for(int j=i+1;j<=n;++j){
int x=a[i]+a[j];
int pos=lower_bound(p+1,p+sz+1,x)-p;
if(x==p[pos]){
G[i].push_back(j+n);
G[j].push_back(i+n);
}
}
for(int i=1;i<=n;++i){
++tim;
if(DFS(i)) ++ans;
}
printf("%d\n",n-ans/2);
return 0;
}
优先级有点小坑
但是调的我吐