HDU-5943 Kingdom of Obsession(二分图最大匹配+数学找规律)
这题真的是三人合力写的,阿忠哥找规律,胖清打了素数表证明了一下特判的正确性,而我呢,就敲了一个匈牙利的板子,最后AC了就提早退场了,感到舒适~
题目大意
给一个n和一个s,列两行数字,第一行是s+1,s+2,…,s+n,第二行是 1,2,…,n,要求第一行每一个数字都要去第二行里找到一个能整除自己的数字进行匹配,如果不能匹配成功就输出”No”,否则就是“Yes”.
思路
阿忠哥看完题,直接拍板:二分图最大匹配!但是一看数字1e9的范围,我表示懵逼,这图我都存不下啊??而且存图这样子一看起码要O( n 2 n^2 n2)。阿忠哥当即立断:n大于1e3咱们就直接输出No了!
对数论知识基本一片空白的我表示费解。阿忠哥表示让胖清打一个素数表,然后发现1e4以下的相邻素数间隔最多只有158,1e3以下的素数相隔最多也就150,所以我们大胆推断,假设加一个0素数相隔多8的话,到1e9也只多了40个,怎么说长度n如果长到了1000以上的话肯定会有两个素数在里面,素数只能和1匹配,这样势必有会一个素数无法匹配,直接输出“No"!
就在我敲完了准备交的时候。。。中国好队友胖清又发现了!
Input
1
10004 0
Output
Case #1: Yes
场面一度十分尴尬,因为我们的特判这个输出的直接就是No了。这个例子里面就是每个数字和自己匹配即可。(实际上我们都默认s>n了,然而并不是)。然后我们又发现,s为1的时候,多出来的那个数字和1匹配,其他的数字都和自己匹配即可,s为2的时候多出来的数字必然是一奇一偶,所以可以分别与1和2匹配,然后再看s为3的时候,多出来的数字必然是一个被3整除的数字,和3匹配,然后剩下的数字奇数和1配对,偶数和2配对,我们就大胆猜想s<n都是可行的,交上去,T了,原来是我怕1e3的特判布星,就写了1e4,实践证明杭电OJ的垃圾评测机O( n 2 n^2 n2)最终1e8的时间复杂度过不了,这好办,按阿忠哥说的改成1e3,不T了就WA了。最后我们终于在4这里发现了问题,如下。
5 6 7 8 9 10 11 12 13
1 2 3 4 5 6 7 8 9
于是我们简单粗暴地判断s<=3都输出”Yes“,又WA了,然后我们开始各种判断奇数偶数啦之类的各种骚,布星,阿忠哥恍然大悟,直接把错位重复的删了,剩下的再跑匈牙利或者直接大于1000特判就行了啊?过了。这题就是个匈牙利裸板加一点点特判。
代码
#include <bits/stdc++.h>
using namespace std;
const long long maxn=1e5;
vector<long long> egs[maxn+5];
long long linker[maxn+5];
bool vis[maxn+5];
bool check[maxn+5];
long long ss[maxn+5];
vector<long long>pri;
bool dfs(long long u)
{
for(long long v=0;v<egs[u].size();v++)
{
long long nxt=egs[u][v];
if(!vis[nxt])
{
vis[nxt]=true;
if(linker[nxt]==-1 || dfs(linker[nxt])){
linker[nxt]=u;
return true;
}
}
}
return false;
}
long long hungary(long long n)
{
n*=2;//图已经是2n个节点了
long long ret=0;
memset(linker,-1,sizeof linker);
for(long long u=1;u<=n;u++)
{
memset(vis,0,sizeof vis);
if(dfs(u)) ret++;
}
return ret;
}
bool solve()
{
long long n,s;
scanf("%lld%lld",&n,&s);
if(s<n)//特判,把重复的删了其实就是交换s和n的位置
{
long long t=s;
s=n;
n=t;
}
if(n>=1000)
{
return false;
}
else
{
for(long long i=1;i<=2*n;i++)
{
egs[i].clear();
}
for(long long i=1;i<=n;i++)
{
long long temp=s+i;
for(long long j=1;j<=n;j++)
{
if(temp%j==0)
{
egs[n+i].push_back(j);
//建图,小技巧,这里有2*n个点,如果直接s+n,1e9的s,RE必死无疑
}
}
}
if(hungary(n)==n)
{
return true;
}
else
{
return false;
}
}
}
int main()
{
//freopen("test.txt","r",stdin);
long long t;
scanf("%lld",&t);
for(long long i=1;i<=t;i++)
{
if(solve())
{
printf("Case #%lld: Yes\n",i);
}
else
{
printf("Case #%lld: No\n",i);
}
}
return 0;
}
今天没有感谢文章了,这个题完全就是我们自己过的,要感谢都感谢队友们的栽培~