Nebius Welcome Round (Div. 1 + Div. 2)(B~E)

B. Vaccination

传送门

思路

判断可以用一个疫苗的话不好搞,所以可以从什么要开一个新的疫苗入手

  • 如果之前没有打开疫苗的话
  • 之前的疫苗已经用完
  • 轮到的这个人不能和之前的一起用这个疫苗

代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2e5+10;
int p[N],hh,tt;
int n,k,d,w;
int a[N];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int sum=0;
        hh=tt=0;
        cin>>n>>k>>d>>w;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            if(tt-hh>=k||tt==0||a[p[hh]]+w<a[i]-d)
            {
                tt=0,sum++,p[tt++]=i;
                //cout<<i;
            }
            else p[tt++]=i;
        }
        cout<<sum<<endl;
    }
}

C. Pull Your Luck

传送门

思路

注意到 n的范围和p范围,所以可以遍历一遍所有的n而不能遍历所有的p,那就遍历所有一遍n,再分析p和n关系


如果在1~n中没有有效答案,再进行分类讨论

  • 如果 n为奇数的话 n ! = ( n + 1 ) ∗ n / 2 n! =(n+1)*n/2 n!=(n+1)n/2 ( n + 1 ) (n+1) (n+1)肯定可以整除2,所有 n !   m o d   n = = 0 n!{\bmod}n==0 n!modn==0所以每经过n次都会回归原点,也就是说n后面的可以不用判断了
  • 如果n为偶数 n ! = ( n / 2 ) ∗ n + n / 2 n!=(n/2)*n+n/2 n!=(n/2)n+n/2所以只要考虑 n / 2 n/2 n/2就行了
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2e5+10;
int minmli[N];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,x,p;
        cin>>n>>x>>p;
        int sum=0,anserw=(n-x)%n;
        bool fl=false;
        for(int i=1;i<=min(n,p);i++)
        {
            sum=(sum+i)%n;
            minmli[i]=sum;
            if(sum==anserw)fl=true;
        }
        if(n%2==0)
        for(int i=1;i<=min(n,p-n);i++)
        {
            if((minmli[i]+n/2)%n==anserw)fl=true;
        }
        //cout<<anserw;
        if(fl)puts("YES");
        else puts("NO");
    }
}

D. Accommodation

传送门

思路

考虑最少,就是看能有多少个 “11”就行了,直接遍历一遍就行

考虑最多,就是看能有多少个“10”,“01”,“00”就行直接dp,一层for就行

两个没有互相影响,且遍历顺序一样所以一起

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 5e5+10;
int m,n;
int l=0,zi=0,zu=0,minsum=0,maxsum;
int f[N];
int main()
{
    scanf("%d%d",&n,&m);
    int a=m/4,b=m/2,tem,tem1;
    for(int tt=1;tt<=n;tt++)
    {
        l=0,zi=0,zu=0;
        for(int i=1;i<=m;i++)
        {
            scanf("%1d",&tem);
            if(i==1)f[i]=0;
            else 
            {
                f[i]=f[i-1];
                if((tem&tem1)!=1)
                {
                    f[i]=max(f[i],f[i-2]+1);
                    //cout<<i<<endl;
                }
            }
            if(tem==1)l++,zi++;
            else zi=0;
            if(zi==2)zu++,zi=0;
            tem1=tem;
            
        }
        //cout<<f[3]<<endl;
        minsum+=min(zu,a)+l-2*min(zu,a);
        maxsum+=l-max(0,a-f[m]);
    }
    printf("%d %d\n",minsum,maxsum);
    
}

E. Routing

传送门

思路

题目意思很长,但其实就是就是找是否存在一个环,这个环上的点只出现一次,并且所有点要么组成这个环,要么和环上的点直接联系,找环可以可以借鉴哈密顿路径的写法, f [ i ] [ j ] f[i][j] f[i][j]表示从i位次最低的点为起点,经过的点集为i,最终到达j的可能性,如果存在f[i][j]==true,并且存在i位次最低的点到j的路就存在环
注意只有一条的边的两个点也算环,单独一个点不算。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
const int N = 20;
map<int,int> cf;           
bool f[1<<N][N];
bool st[N][N];
int d[N];
int n,m;
bool cff[N];
bool cr[N];
bool fl=false;
int lowbit(int x)  // 返回末尾的1
{
    return x & -x;
}
bool check(int x)
{
    //cout<<x<<endl;
    memset(cff,0,sizeof cff);
    int l=0;
    for(int i=0;i<n;i++)if(x&(1<<i))cff[i]=true,l++;
    for(int i=0;i<n;i++)
    {
        if(cff[i])continue;
        for(int j=0;j<n;j++)
        {
            if(cff[j]&&st[i][j]){l++;break;}
        }
    }
    if(l!=n)return false;
    //cout<<x<<endl;
    //if(l==n)return true;
    fl=true;
    for(int i=0;i<n;i++)
    {
        if(cff[i])continue;
        for(int j=0;j<n;j++)
        {
            if(cff[j]&&st[i][j])
            {
                d[i]=j;
                break;
            }
        }
    }
    int zz=-1,yy;
    for(int i=0;i<n;i++)
    {
        if(f[x][i]&&st[cf[lowbit(x)]][i])zz=i;
    }
    d[zz]=cf[lowbit(x)];
    x-=(1<<zz);
    yy=zz;
    //cout<<x;
    while(x)
    {
        zz=-1;
        for(int i=0;i<n;i++)
        {
            if(f[x][i]&&st[i][yy])zz=i;
        }
        d[zz]=yy;
        x-=(1<<zz);
        yy=zz;
    }
    return true;
}
int main()
{
    
    cin>>n>>m;
    for(int i=0;i<n;i++)cf[1<<i]=i;
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        a--,b--;
        st[a][b]=st[b][a]=true;
    }
    for(int i=0;i<n;i++)f[1<<i][i]=true;
    for(int i=1;i<1<<n;i++)
    {
        for(int j=cf[lowbit(i)]+1;j<n;j++)
        {
            if(i&(1<<j))
            {
                for(int k=cf[lowbit(i)];k<n;k++)
                {
                    if(st[k][j]&&(i-(1<<j))&(1<<k))
                    {
                        f[i][j]|=f[i-(1<<j)][k];
                    }
                }
            }
        }
    }
    for(int i=0;i<1<<n;i++)
    {
        bool fl=false;
        for(int j=0;j<n;j++)
        {
            if(f[i][j]&&st[cf[lowbit(i)]][j])fl=true;
        }
        if(fl&&check(i))break;
    }
    //if(check(6374))cout<<"kjf";
    //for(int i=0;i<n;i++)cout<<d[i]+1<<" ";
    //cout<<st[0][1];
    if(fl)
    {
        puts("YES");
        for(int i=0;i<n;i++)cout<<d[i]+1<<" ";
    }
    else puts("NO");
}

ps:搞了一下午。。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值