- Kingdom of Obsession
- 這一題需要思維抽象能力,如果僅看到問題的表面(數論),則無從下手。
- 問題的實質是將1, 2, 3, …, n這n個數(記爲y)與s+1, s+2, s+3, … s+n這n個數(記爲x)建立一一映射,並且每個映射都滿足x%y=0。
- x%y=0可以寫成x=ky (k>0, k∈N),即x爲y的倍數。
- 若s<n,則x與y有一部分相同,我們可以將相同的部分與自身映射,使sub=n-s, n-=sub, s+=sub(此操作等價於swap(s,n)),問題就被簡化爲x與y不重合的情況。
- 既然x與y無交集部分,且x爲y的倍數,說明x集合中不可以同時有兩個素數(一個素數可以使其%1)。本地用歐拉篩篩出所有1e9內素數,統計出相鄰素數之間的最大間隔,可知相鄰素數之間間隔不會超過1000。
- 所以,若n≥1000,則一定無解。
- n<1000時,將x與y兩個集合看成二分圖,兩點之間存在邊的條件爲x%y=0。用匈牙利算法可以計算出二分圖的最大匹配數。若最大匹配數≠n,則無解,否則有解。
代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
bool g[1010][1010];
int linker[1010],uN,vN;
bool used[1010];
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()
{
int T,kcase=0;
scanf("%d",&T);
while(T--)
{
int n,s;
scanf("%d%d",&n,&s);
if(n>s)
{
swap(n,s);
}
if(n>1000)
{
printf("Case #%d: No\n",++kcase);
continue;
}
memset(g,false,sizeof(g));
uN=vN=n;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
if(!((s+j)%i))
{
g[j-1][i-1]=true;
}
}
}
if(hungary()==n)
{
printf("Case #%d: Yes\n",++kcase);
}
else
{
printf("Case #%d: No\n",++kcase);
}
}
return 0;
}