HDU 5943 Kingdom of Obsession(二分图匹配+数论)

来源:互联网 发布:税收数据质量管理 编辑:程序博客网 时间:2024/05/19 13:59

Kingdom of Obsession

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1764    Accepted Submission(s): 511
Problem Description
There is a kindom of obsession, so people in this kingdom do things very strictly.
They name themselves in integer, and there are n people with their id continuous (s+1,s+2,,s+n) standing in a line in arbitrary order, be more obsessively, people with id x wants to stand at yth position which satisfy
xmody=0
Is there any way to satisfy everyone's requirement?
Input
First line contains an integer T, which indicates the number of test cases.
Every test case contains one line with two integers n,s.

Limits
1T100.
1n109.
0s109.
Output
For every test case, you should output 'Case #x: y', wherex indicates the case number and counts from 1 andy is the result string.
If there is any way to satisfy everyone's requirement, y equals 'Yes', otherwise y equals 'No'.
Sample Input
25 144 11
Sample Output
Case #1: NoCase #2: Yes
Source
2016年中国大学生程序设计竞赛(杭州)  



        大致题意是给你从n开始的s个连续的数字,例如n=15,s=3,那么对应16、17、18三个数字。然后,每个数字的可行放法是放在它的因子对应的位置上,例如8可以放到第1、2、4、8个位置上。问你是否存在一种摆法使得这s个数字能够合法的排成从1~s的一列。

        一开始觉得是一个找规律的题目,但是仔细分析之后可以发现这之中还是可以体现一些算法的。对于一个数字i它可以放到它的约数对应的位置上,然后每个位置和数字一一对应,很容易发现这是一个匹配问题。如果数字能放到1~s的某一个位置,那么就连一条边,最后跑一遍匈牙利算法,看是否存在完美匹配即可。然而,此题数据范围较大,对于 O(N^2M)的匈牙利算法来说哦实在差的太远。

        进一步研究数据,我们可以发现,一个数字i是否可以放,无非就是看它的约数对应的位置是否被放完了,如果所有约数的位置都被放完了,那么显然这个数字就放不了,答案就是NO。如此一来,有一类数字就比较显眼了,这就是质数。如果在s+1~s+n+1这个区间内有两个质数,那么结果就很有可能是NO。可是,我如何判定区间内有几个质数呢?观察质数的出现规律我们可以发现,质数的间隔其实是比较小的。于是经过打表,我们可以得出结论,在1e9范围内,相邻两个质数的差最多不会超过255.这也就意味着每255*2个数字中至少会有两个质数,即长度大于510的区间一定含有两个质数,那么其对应结果就很有可能是NO。于是我们就可以分类讨论,当区间长大于510的时候,也许可以直接输出NO,否则在长度较短的时候,我使用匈牙利算法暴力解。

         细心的读者可能已经发现,上一段我在叙述长度大于510的区间的时候,用的是“可能”、“或许”。对,这样是有问题的。例如,n=2,s=5,那么对应的数字就是3、4、5、6、7,这些数字中有三个质数,但是结果却是YES。也就意味着,一个区间内有两个或者以上的质数并不能直接说明结果就是NO,为什么呢?我们发现,即使是质数,它也有两个约数,那就是1和它本身。如果它本身也是一个可行的排位的话,那么这个数字就不能当成我们想要的“质数”进行统计处理。我自己在做这道题的时候就考虑到这了,但是后来没有想到什么解决的方法。正确解法的话,我们继续观察可以发现当s>n时,就会出现这种情况。那么能不能不让s>n的情况出现,也就是说当s>n的时候我交换s与n是否会对结果产生影响呢?事实证明是不会的,我把2个数字往后移1000位和1000个数字往后移2位,是等价的。道理也很显然,因为1000个数字往后移2位,相当于从3~1000这998个数字根本没有发生任何变化,他们原本是数字i,那么我就把它放到第i个位置。变化的只是第一个和第二个数字,于是就相当于是把2个数字往后移1000位。两个答案等价,所以当出现s>n的时候,我直接交换即可。

        通过这样一个巧妙的交换处理,我们解决了方法中的缺陷。然后结合之前的分类+暴力思想,我们就能轻松的解决这道题目。数论无其不巧呀!具体见代码:

using namespace std;#include<bits/stdc++.h>#define N 2010using namespace std;namespace Hungry{struct edge{int x,y,next;} g[N*N];int link[N],ls[N],n,m,e;bool cover[N];inline bool find(int i){int k=ls[i];while (k>0){if (!cover[g[k].y]){cover[g[k].y]=1;if (find(link[g[k].y])||(link[g[k].y]==0)){link[g[k].y]=i;return 1;}} k=g[k].next;}return 0;}inline int hungry(){int ans=0;for(int i=1;i<=n;i++){memset(cover,0,sizeof(cover));if (find(i)) ans++;}return ans;}inline void add(int x,int y)     //  x==y is available {g[++e].x=x;g[e].y=y;g[e].next=ls[x];ls[x]=e;}}int main(){    int T,tt=0;    scanf("%d",&T);    while (T--)    {    using namespace Hungry;        scanf("%d%d",&n,&m);        if (m<n) swap(n,m);        if (n<510)        {            e=0;            memset(ls,0,sizeof(ls));            memset(link,0,sizeof(link));            for (int i=1;i<=n;i++)                for (int j=1;j<=n;j++)if ((i+m)%j==0) add(i,j);            int x=hungry();            if (x==n) printf("Case #%d: Yes\n",++tt);            else printf("Case #%d: No\n",++tt);        }else printf("Case #%d: No\n",++tt);    }    return 0;}


阅读全文
0 0
原创粉丝点击