《LGJOJ 8.24》 测试总结
这波贵物了属于是
\(T1\) 黑暗料理



奇偶分开,二分图,要用到 \(Miller\_Rabin\) 判素数。
点击查看代码
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int MAXN=760;
const LL inf=1e18;
int n,T,st,de;
int a[MAXN];
struct daduoli {
int f,t,c;
}que[MAXN*MAXN*2];
int cnt=1,h[MAXN];
void add(int f,int t,int c) {
que[++cnt].f=h[f];
que[cnt].t=t;
que[cnt].c=c;
h[f]=cnt;
}
void adline(int x,int y,int w) {
add(x,y,w);
add(y,x,0);
}
int dis[MAXN],cur[MAXN];
bool bfs() {
for(int i=1;i<=n+2;++i) {
dis[i]=-2;
cur[i]=h[i];
}
dis[st]=0;
queue<int> q;
q.push(st);
while(!q.empty()) {
int u=q.front();
q.pop();
for(int i=h[u];i;i=que[i].f) {
int t=que[i].t;
if(dis[t]==-2&&que[i].c) {
dis[t]=dis[u]+1;
q.push(t);
if(t==de) return true;
}
}
}
return false;
}
LL dinic(LL u,LL flow) {
if(u==de) return flow;
LL res=0;
for(int i=cur[u];i&&flow;i=que[cur[u]].f) {
cur[u]=i;
int t=que[i].t;
if(!que[i].c||dis[u]+1!=dis[t]) continue;
LL k=dinic(t,min(flow,(LL)que[i].c));
if(!k) dis[t]=-2;
flow-=k; res+=k;
que[i].c-=k;
que[i^1].c+=k;
}
return res;
}
int prime[10+10]={2,3,5,7,11,233,331},tim=7;
LL ksm(LL x,LL y,LL MODD) {
LL ret=1;
while(y) {
if(y&1) ret=ret*x%MODD;
x=x*x%MODD;
y>>=1;
}
return ret;
}
LL mul(LL x,LL y,LL MODD) {
LL ret=0;
while(y) {
if(y&1) ret=(ret+x)%MODD;
x=(x+x)%MODD;
y>>=1;
}
return ret;
}
bool miller_rabin(LL a,LL n) {
LL s=n-1,r=0;
while(!(s&1)) {
s>>=1;
++r;
}
LL x=ksm(a,s,n);
for(int i=0;i<r;++i) {
LL tmp=mul(x,x,n);
if(x!=1&&x!=n-1&&tmp==1) return false;
x=tmp;
}
return (x==1);
}
bool check(int n) {
if(n==1) return false;
for(int i=0;i<tim;++i) {
if(n==prime[i]) return true;
if(!miller_rabin(prime[i],n)) {
return false;
}
}
return true;
}
int main() {
scanf("%d",&T);
while(T--) {
cnt=1; memset(h,0,sizeof(h));
scanf("%d",&n);
st=n+1; de=n+2;
for(int i=1;i<=n;++i) {
scanf("%d",&a[i]);
}
bool sf=0;
int ans=0;
for(int i=1;i<=n;++i) {
if(a[i]==1&&sf) {
++ans;
continue;
}
if(a[i]==1) sf=1;
if(a[i]%2==1) adline(st,i,1);
else adline(i,de,1);
for(int j=i+1;j<=n;++j) {
if(i==j) continue;
if(check(a[i]+a[j])) {
if(a[i]%2==1) adline(i,j,1);
else adline(j,i,1);
}
}
}
while(bfs()) ans+=dinic(st,inf);
printf("%d\n",n-ans);
}
return 0;
}
\(T2\) 爆炸



考虑并查集,如果 \((i,j)\) 有炸弹,就将第 \(i\) 行第 \(j\) 列连起来。
但是一次爆炸必须要一个炸弹来引燃,也就是说对于一般情况而言,要失去一个行或列的贡献,但是如果有环就是另一回事了,怎么判环呢,就是炸弹数量大于等于所能炸取的行列之和。
时间复杂度 \(O(nm)\)
点击查看代码
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int MAXN=6010;
int n,m,k,b,ans;
int fa[MAXN*2],sz[MAXN*2],du[MAXN];
char ch[3010][3010];
int find(int x) {
return (fa[x]==x?x:fa[x]=find(fa[x]));
}
void merge(int x,int y) {
int xx=find(x);
int yy=find(y);
if(xx==yy) return ;
fa[yy]=xx;
sz[xx]+=sz[yy];
++sz[xx];
++du[x]; ++du[y];
}
vector<int> e[MAXN];
int sf[MAXN];
int main() {
scanf("%d%d%d%d",&n,&m,&k,&b);
for(int i=1;i<=n;++i) {
for(int j=1;j<=m;++j) {
ch[i][j]=getchar();
while(ch[i][j]!='k'&&ch[i][j]!='b'&&ch[i][j]!='.') ch[i][j]=getchar();
}
}
for(int i=1;i<=n+m;++i) {
fa[i]=i; sz[i]=0;
}
for(int i=1;i<=n;++i) {
for(int j=1;j<=m;++j) {
if(ch[i][j]=='b') {
merge(i,n+j);
}
}
}
for(int i=1;i<=n+m;++i) {
fa[i]=find(fa[i]);
e[fa[i]].push_back(i);
}
for(int i=1;i<=n+m;++i) {
int ls=0,p=0;
if(fa[i]!=i) continue;
for(auto t:e[i]) {
++p;
if(t<=n) {
sf[t]=i;
for(int j=1;j<=m;++j) {
if(ch[t][j]=='k'&&sf[n+j]!=i) {
++ls;
}
}
}
else {
sf[t]=i;
for(int j=1;j<=n;++j) {
if(ch[j][t-n]=='k'&&sf[j]!=i) {
++ls;
}
}
}
}
if(sz[i]>=p) ans=max(ans,ls);
for(auto t:e[i]) {
if(du[t]>1) continue;
int lss=ls;
if(t<=n) {
for(int j=1;j<=m;++j) {
if(ch[t][j]=='k'&&sf[n+j]!=i) {
--lss;
}
}
}
else {
for(int j=1;j<=n;++j) {
if(ch[j][t-n]=='k'&&sf[j]!=i) {
--lss;
}
}
}
ans=max(ans,lss);
}
}
printf("%d\n",ans);
return 0;
}

浙公网安备 33010602011771号