zoukankan      html  css  js  c++  java
  • Problem 2. number题解

    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;
    }
  • 相关阅读:
    合并排序二
    合并排序
    理解Windows消息循环机制
    直接插入排序
    关于typedef的用法总结
    迭代器的抽象
    C++基础--malloc和new的区别
    C++基础--sizeof和strlen的区别
    C++ VS编译问题--LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
    SSL--Windows下生成OpenSSL自签证书
  • 原文地址:https://www.cnblogs.com/LJB666/p/10665230.html
Copyright © 2011-2022 走看看