现场赛的铜牌题,没有搞出来挺遗憾的
题意:如果i%j==0,那么说(i,j)是可以匹配的
题目问:(s+1,s+2,……,s+n),(1,2,……,n)这两个数组能否找到某种对应方式,使得完全匹配(也就是说等于n)
一开始的思路是:素数是很特殊的数,当值很大的时候,(s+1,s+2,……,s+n)不能出现两个素数
但是这个判定条件其实很奇怪:因为不知道怎么定义值很大
那么:想着小数据打表:什么叫做小数据呢?
n很小:因为二分图匹配的算法是O(NM),所以不妨定在1000
这个范围内的直接跑算法
那么当n比较大的时候呢?直接输出no吗?
思路接近了,但是有一种很极端的情况
n=1001,s=1
这组数据的意思是:(2,3,4,……,1002)来匹配(1,2,3,4,……,1001)
发现什么了吗?中间有很多个数都是重复的!重复的数是一定可以自己匹配自己的
那么这组算大数据吗?!不算:因为s很小
所以,如果n很大,s很小,会有很多个重叠的部分:先删去重叠的,然后暴力匹配
当n很大,s也很大:直接输出no
其实是有理论依据的:因为n和s都是大于1000的
在1e9的范围内,相邻两个素数的最大距离是300+
那么意味着,在(s+1,s+2,……,s+n)中,删去与(1,2,……,n)重复的部分,肯定是有两个素数的,他们是不可能同时匹配到1的
理论上的一个文字证明吧
代码如下:(我的ccpc的铜牌,桑心)
#include<bits/stdc++.h>
using namespace std;
const int maxn=1050;
int uN,vN;
int T,n,s;
int g[maxn][maxn];
int linker[maxn];
bool used[maxn];
bool dfs(int u){
for(int v=0;v<vN;v++)
if (g[u][v]&&!used[v]){
used[v]=true;
if (linker[v]==-1||dfs(linker[v])){
linker[v]=u;
return true;
}
}
return false;
}
int hungary(){
int res=0;
memset(linker,-1,sizeof(linker));
for(int u=0;u<uN;u++){
memset(used,false,sizeof(used));
if (dfs(u)) res++;
}
return res;
}
int main(){
scanf("%d",&T);
for(int Case=1;Case<=T;Case++){
scanf("%d%d",&n,&s);
memset(g,0,sizeof(g));
if (n<=1000){
uN=vN=n;
for(int i=s+1;i<=s+n;i++)
for(int j=1;j<=n;j++)
if (i%j==0)
g[i-s-1][j-1]=1;
if (hungary()==n)
printf("Case #%d: Yes\n",Case);
else
printf("Case #%d: No\n",Case);
}
else if (s<=1000){
uN=vN=s;
for(int i=n+1;i<=n+s;i++)
for(int j=1;j<=s;j++)
if (i%j==0)
g[i-n-1][j-1]=1;
if (hungary()==s)
printf("Case #%d: Yes\n",Case);
else
printf("Case #%d: No\n",Case);
}
else
printf("Case #%d: No\n",Case);
}
return 0;
}