SDUT 2021 Summer Individual Contest - 7

J - Programming Tutors

题目大意:给n个学生和n个教练的坐标,按对分配,使得学生和教练的最大距离最小,求出这个最大距离的最小值。
思路:最大距离的最小值可以通过二分求得,之前接触过了。那么如何二分出一个最大距离的最小值需要用二分图最大匹配,最大匹配返回的是可以匹配的个数,如果个数是n的话,说明可以匹配,继续缩小版边界,最后二分的结果就是满足最大匹配的最小值。

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<vector>
#include<map>
#include<queue>
#define int long long

const int N=300,INF=0x3f3f3f3f,mod=1e9+7;
using namespace std;
struct node
{
    int x,y;

} s[N],t[N];

int n;
int g[N][N];
int match[N];
bool st[N];
int mid;

bool find(int x)
{
    for(int i=1;i<=n;i++)
    {
        if(g[i][x]<=mid&&!st[i])
        {
            st[i]=true;
            if(match[i]==0||find(match[i]))
            {
                match[i]=x;
                return true;
            }
        }
    }

    return false;
}
int check()
{
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        memset(st,0,sizeof st);
        if(find(i))cnt++;
    }

    return cnt;
}
signed main()
{
    cin>>n;
    for(int i=1; i<=n; i++)
    {
        int a,b;
        cin>>a>>b;
        s[i]= {a,b};
    }
    for(int i=1; i<=n; i++)
    {
        int a,b;
        cin>>a>>b;
        t[i]= {a,b};
    }

    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            g[i][j]=abs(s[i].x-t[j].x) + abs(s[i].y-t[j].y);
        }
    }
    int l=0,r=INF;
    while(l<r)
    {
        memset(match,0,sizeof match);
        mid=l+r>>1;
        if(check()==n)r=mid;
        else l=mid+1;
    }

     cout<<l<<endl;
    
}

L - Sticky Situation

题意:给定一个 n ,和 n 个数, 看存不存在三个数可以构成三角形。
在这里插入图片描述
思路:先从小到大排序,原因是可以得到性质。
对于有相对顺序的三个数字 a i , a k , a m ( i < k < m ) a_i,a_k,a_m(i<k<m) ai,ak,am(i<k<m),因为m是最大的数,所以 a i < a m + a k a_i<a_m+a_k ai<am+ak, a k < a m + a i a_k<a_m+a_i ak<am+ai 显然成立。对于 a i + a k > a m a_i+a_k>a_m ai+ak>am这种情况,我们希望它尽可能成立,这时候希望 a m a_m am尽可能小, a i + a k a_i+a_k ai+ak尽可能大,但仍要满足下标关系,所以每次只需要判定 a i + a i + 1 与 a i + 2 a_i+a_{i+1}与a_{i+2} ai+ai+1ai+2的关系即可以判定答案是否存在。

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
typedef long long LL;
LL a[N];
int main()
{
    LL n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+1+n);
    for(int i=1;i<=n;i++)
    {
        if(a[i]+a[i+1]>a[i+2]&&a[i+1]+a[i+2]>a[i]&&a[i]+a[i+2]>a[i+1])
        {
            cout<<"possible";
            return 0;
        }
    }
    cout<<"impossible";
}

I - Older Brother

题意:给定一个 q q q q q q 的范围如下图所示:
在这里插入图片描述
要你判断这个 q 是不是某个质数 p 的某个次方,即判断 q = p k ( k > = 1 ) q=p^k( k>=1) q=pk(k>=1) 是否成立。
思路:首先当 k = 1 k=1 k=1的时候直接输出 y e s yes yes, 即 当 q q q 是一个素数。如果当 q q q 不是素数可以筛出 1 1 1 n n n 之前所有的素数,然后枚举其所有的指数并标记,看 q q q 是不是某个质数的某个次方的值。
但是从q的范围来看不能枚举出1~q之前所有的素数,这时候我们可以抓住一点性质,如果判断一个数是否为质数只需要 n \sqrt{n} n 的时间复杂度,即 k = 1 的 情 况 很 容 易 判 断 k=1的情况很容易判断 k=1,对于 k > = 2 k>=2 k>=2 的情况,最大的质数也只会在 1 e 9 \sqrt{1e9} 1e9 的范围筛掉 1 e 9 1e9 1e9 的 q ,所以这种情况只需要枚举 1 e 9 \sqrt{1e9} 1e9 范围内的质数,再指数枚举它的次方即可,复杂度大概是 n ⋅ l o g n \sqrt{n}·log_n n logn

#include <iostream>
#include <algorithm>
using namespace std;
const int N= 1e5+10;
const int M= 1e9+10;
typedef long long LL;
int primes[N], cnt;
bool st[N];
bool vis[N];
bool is_prime(int x)
{
    if (x < 2) return false;
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)
            return false;
    return true;
}
void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ )//
        {
            st[primes[j] * i] = true;//如果下面i % primes[j] != 0,因为primes[j]
//从小到大枚举,所以primes[j]< i 的最小质因子,所以primes[j]是primes[j]* i 的最小值因子 
            if (i % primes[j] == 0) break;
            //如果i % primes[j] == 0,因为primes[j]是从小到大枚举的 
// 那么primes[j]一定是i的最小质因子,也是primes[j]* i 的最小值因子 
        }
    }
}
int main()
{
    int n;
    cin >> n;
    if(is_prime(n)) cout<<"yes";
    else 
    {
        get_primes(N);
        for(int i=0;i<cnt;i++)
        {
            //cout<<primes[i]<<endl;
            for(LL j=primes[i];j<=M;j*=primes[i])
            {
                if(n==j) {cout<<"yes";return 0;}
            }
        }
        cout<<"no";
    }
    
    return 0;
}

C - Brexit

题意:给 n , m , st , ed。 代表n个点,m条边,自己所在的城市st, 开始沦陷的城市ed,沦陷的城市周围有许多邻城,如果对于某个城市来说,如果周围沦陷的城市大于等于自身周围城市个数的一半,那么自身这个城市也将沦陷,也可以理解为被攻占。判断最后自己所在的城市有没有沦陷。
在这里插入图片描述
思路:开两个数组,一个村邻城个数,一个存沦陷的邻城个数。存边的时候把每个点的邻城出度记录一下,以便查询到每一个点的邻城有多少。 d f s dfs dfs 遍历所有沦陷的城市,告诉这个城市周围所有的城市,让邻城存沦陷的邻城的那个数组 + + ++ ++

#include <iostream>
#include<cstring>
using namespace std;
const int N = 3e5+10;
int vis[N];//遍历过的点不再遍历
typedef long long LL;
int e[2*N],ne[2*N],h[2*N],idx;

int g[N],g1[N];//周围的邻城个数,周围沦陷的城市个数

void add(int a, int b)  // 添加一条边a->b
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ,g[a]++;
}

LL n,m,st,le;
void dfs(int x)
{  
    vis[x]=1;//标记所有的沦陷的城市
    for(int i=h[x];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(vis[j]) continue;
        g1[j]++;//告诉所有的邻城 我被攻占了
        if(g1[j]*2>=g[j])//判断这些邻城,看看他们是否跟着沦陷
        {
            dfs(j);//如果满足条件就递归下去
        }
    }
    return ;
}

int main()
{
    memset(h, -1, sizeof h);
 
    scanf("%ld%ld%ld%ld",&n,&m,&st,&le);
    while (m -- )
    {
        LL a,b;
        scanf("%lld%lld", &a, &b);
        add(a,b);
        add(b,a);
        
    }
    dfs(le);
    if(!vis[st])  printf("stay");
    else printf("leave");
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值