number:数学+二分图匹配
首先,如果S<N,那么S+1,S+2...N这些数直接放在S+1,S+2...N的位置上(如果其他数x放在这些位置上面,这些数不放在对应位置,那么x一定能放在这些数放的位置,所以直接交换即可)所以可以直接将S和N调换,缩小N。接着看N个连续的数,如果这里面有两个素数,则肯定无解,而在1e9的范围内,素数间隔最大是低于600的,我们就可以通过二分图匹配(s+i与其因数建边)求出最大匹配,若最大匹配为N,则为Yes。实际上,能满足的N其实最大为30多,而菜菜的jyb只枚举到了很多20多的答案,所以为了卡掉暴力匹配的做法(但还是很良心地给了5个点),不得不多设置了很多数据组数。
迷之数学规律,n>600时就会至少有两个素数出现,不符合题意,然后我们一下子就将1e9的数据变成了n<600,之后进行裸的二分图匹配即可,代码如下
#include<bits/stdc++.h> using namespace std; const int maxn=1010; const int N=605; bool vis[maxn]; int match[maxn]; int ditu[N][N]; int T,n,s; bool dfs(int x)//匈牙利算法 { if(x==0) { return false; } for(int i=1;i<=n;i++) { if(!vis[i] && ditu[i][x]) { vis[i]=true; if(!match[i]||dfs(match[i])) { match[i]=x; return true; } } } return false; } int main() { freopen("number.in","r",stdin); freopen("number.out","w",stdout); scanf("%d",&T); while(T--) { scanf("%d%d",&n,&s); if(s<n) { swap(s,n); } if(n>600) { printf("No "); continue; } memset(ditu,0,sizeof(ditu)); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if((i+s)%j==0)//能够整除的数之间建边,这段代码的灵魂所在 { ditu[i][j]=1; } } } memset(match,0,sizeof(match)); int ans=0; for(int i=1;i<=n;i++) { memset(vis,0,sizeof(vis)); if(dfs(i)) { ans++; } } if(ans==n) { printf("Yes "); } else { printf("No "); } } return 0; }