• 「国庆训练」Kingdom of Obsession(HDU-5943)


    题意

    给定(s,n),把(s+1,s+2,...,s+n)(n)个数填到(1,2,...,n)里,要求(x)只能填到(x)的因子的位置(即题目中(x\%y=0)那么x才能放在y位置的要求),问是否能够把所有数都填上去。

    分析

    建模之后就是条二分图的板子题。
    注意到一个有趣的事实:如果([s+1,s+n])中有两个质数,那他们肯定完蛋。因为它们一定都会和1连边然后翻车。
    这意味着什么呢?在(10^9)的范围里面,质数最大的间隔是282(我抄网上的结论的,正确不保证,反正不多),那么我们就可以认定如果n比这个数更大一定是No。
    然后就可以快乐建图了,把取模为0的建一条有向边,看看最后能否找到完美匹配即可。
    实现上,s应当比n大。为什么?如果(s<n),那么([s+1,n])直接放在自己的位置上即可,因为不可能放在比他们更大的地方了(集合的交):那爽死了,我们只需要考虑([1,s])与剩下([n+1,s+n])的匹配即可,这个东西的实质就是n、s交换。有没有其他数(k)放在这些位置上面(如一个数(x))然后这些数字没法放到其他数字的反例呢?没有哦,因为如果(k)能放在([s+1,n])的对应位置,那么作为这个数本身的(x)一定能放在(k)上。所以得到结论:可以直接将(s)(n)调换来缩小(n)

    代码

    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <stack>
    #define MP make_pair
    #define PB push_back
    #define fi first
    #define se second
    #define ZERO(x) memset((x), 0, sizeof(x))
    #define ALL(x) (x).begin(),(x).end()
    #define rep(i, a, b) for (int i = (a); i <= (b); ++i)
    #define per(i, a, b) for (int i = (a); i >= (b); --i)
    #define QUICKIO                  
        ios::sync_with_stdio(false); 
        cin.tie(0);                  
        cout.tie(0);
    #define MS(x,y) memset(x,y,sizeof(x))
    using namespace std;
    typedef long long ll;
    
    const int MAXN=2018;// actually, max distance: 282
    bool mat[MAXN][MAXN];
    bool is_prime(int x)
    {
    	if(x<=1) return false;
    	else for(ll k=2;k*k<=ll(x);++k)
    		 {
    			 if(x%k==0) return false;
    		 }
    	return true;
    }
    
    int linker[MAXN];
    bool vis[MAXN];
    
    int n;
    bool dfs(int x)
    {
    	rep(i,1,n) if(mat[x][i] && !vis[i])
    	{
    		vis[i]=true;
                    if(linker[i]==-1 || dfs(linker[i]))
    		{
    			linker[i]=x;
    			return true;
    		}
    	}
    	return false;
    }
    
    int hungary()
    {
    	MS(linker,-1);
    	int ans=0;
    	rep(i,1,n)
    	{
    		ZERO(vis); // 注意这一行,应当是每一次清空
    	 	if(dfs(i)) ans++;
    	}
    	return ans;
    }
    
    int main()
    {
    	int T; scanf("%d",&T);
    	rep(kase, 1, T)
    	{
    		int primecnt=0;
    		int s;
    		ZERO(mat);
    		scanf("%d%d", &n, &s);
    		if(s<n) swap(s,n); // s should be bigger
    		if(n>1000)
    		{
    			printf("Case #%d: No
    ", kase);
    			continue;
    		}
    		rep(i,1,n)
    		{
    			if(is_prime(s+i)) primecnt++;
    			if(primecnt>1) break;
    		}
    		if(primecnt<=1)
    		{
    			rep(i,1,n)
    			{
    				int t=s+i;
    				rep(j,1,n) if(t%j==0)
    					mat[i][j]=true;
    			}
    			if(hungary()!=n)
    				printf("Case #%d: No
    ", kase);
    			else printf("Case #%d: Yes
    ", kase);
    		}
    		else printf("Case #%d: No
    ", kase);
    	}
    	return 0;
    }
    
    如非注明,原创内容遵循GFDLv1.3发布;其中的代码遵循GPLv3发布。
  • 相关阅读:
    artdialog4.1.7 中父页面给子页面传值
    Sql Server按树形结构排序查询表记录
    js控制滚动条平滑滚动到制定位置
    sql实现对多个条件分组排序方法和区别
    css渐变颜色在线制作
    c#中文转全拼或首拼
    Aspose Cells 添加数据验证(动态下拉列表验证)
    jQuery 插件autocomplete
    导出excel时,以form方式提交json数据
    asp.Net2.0中TextBox设置只读后后台获取不到值的解决方法
  • 原文地址:https://www.cnblogs.com/samhx/p/HDU-5943.html
Copyright © 2020-2023  润新知