• AtCoder Beginner Contest 190


    AtCoder Beginner Contest 190

    不难。

    A - Very Very Primitive Game

    题意:两个人吃糖,每次吃一颗,(C=0)表示第一个人先吃,(C=1)表示第二个人先吃,先无糖可吃的人就输了,问谁赢。

    简单分类讨论,如果差值大于(1)一定是糖多的赢,对(abs(A-B)=1)的特殊处理一下即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 200005
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int main()
    {
    	int A=read(),B=read(),C=read();
    	if(A-B>=2)return puts("Takahashi"),0;
    	if(B-A>=2)return puts("Aoki"),0;
    	if(C==1&&A>=B)return puts("Takahashi"),0;
    	if(C==1&&A<B)return puts("Aoki"),0;
    	if(C==0&&B>=A)return puts("Aoki"),0;
    	return puts("Takahashi"),0;
    }
    

    B - Magic 3

    题意:一个人用(n)次技能打怪物,第(i)个技能触发时间为(x_i),威力为(y_i),怪物能免疫触发时间大于等于(S)技能的和威力小于等于(D)的技能,问是否有技能能够打到怪物身上。

    按顺序读入,判断是否有满足条件的技能即可(ABC第二题比第一题简单是传统艺能吗

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 200005
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int n,S,D;
    int main()
    {
    	n=read();S=read();D=read();
    	while(n--)
    	{
    		int x=read(),y=read();
    		if(x<S&&y>D)return puts("Yes"),0;
    	}
    	return puts("No"),0;
    }
    

    C - Bowls and Dishes

    题意:(n)个盘子(m)个条件,第(i)个条件被满足当且仅当第(a_i)个盘子和第(b_i)个盘子都不为空。有(k)个人过来,第(i)个人可以往第(c_i)个盘子里放一个球,或往第(d_i)个盘子里边放一个球,问最多有多少条件被满足。

    感觉应该是有贪心或者其他的做法的,但是这题(k)很小,因此直接二进制枚举第(i)个人放到第(c_i)个中还是第(d_i)个中,之后(O(n))统计一下答案即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 200005
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int n,m,k,a[N],b[N],c[N],d[N],vis[101];
    int main()
    {
    	n=read();m=read();
    	for(int i=1;i<=m;i++)
    	{
    		a[i]=read();
    		b[i]=read();
    	}
    	k=read();
    	for(int i=1;i<=k;i++)
    	{
    		c[i]=read();
    		d[i]=read();
    	}
    	int maxn=0;
    	for(int i=0;i<(1<<k);i++)
    	{
    		memset(vis,0,sizeof(vis));
    		for(int j=1;j<=k;j++)
    		{
    			if(i&(1<<(j-1)))vis[c[j]]=1;
    			else vis[d[j]]=1;
    		}
    		int ans=0;
    		for(int j=1;j<=m;j++)ans+=(vis[a[j]]&vis[b[j]]);
    		maxn=max(maxn,ans);
    	}
    	printf("%d
    ",maxn);
    	return 0;
    }
    

    D - Staircase Sequences

    题意:问和为(N)公差为(1)的等差数列的个数。

    看到等差数列求和就直接列求和公式,设(x)为首项,(k)为项数,则:

    [frac{(x+(x+k-1)) imes k}{2}=N ]

    (2)移过去

    [(2x+k-1) imes k=2N ]

    那很明显(k)就是(2N)的一个因子,而一个满足条件的(k)需要让(x)为正整数,(O(sqrt {N}))枚举(2N)的因子即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 200005
    #define int long long
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int n,ans;
    int check(int k)
    {
    	if(((n/k)+1-k)%2!=0)return 0;
    	return 1;
    }
    signed main()
    {
    	n=read()*2ll;
    	for(int i=1;i*i<=n;i++)
    	{
    		if(n%i==0)
    		{
    			ans+=check(i);
    			if(i*i!=n)ans+=check(n/i);
    		}
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    E - Magical Ornament

    题意:有(N)种珠子,(M)种排列方式,第(i)种珠子和第(j)种珠子可以挨在一起摆放当且仅当存在(a_x=i,b_x=j)(a_x=j,b_x=i),现在有(k)种珠子要穿在一起,求串的最小长度。

    正解好像是(O(2^KK^2+K(N+M)))的,我写的是(O(2^KK^3+K(N+M)))(dp+bfs)

    我这个做法还是比较好想的,看到这熟悉的形式,就想到了将(a_x)(b_x)间连一条无向边,那么取完(i)再取(j)的最优方式就是在这张图上把(i)(j)最短路上的珠子都取了。

    那首先就可以预处理出来(dis(i,j))表示取完(i)再取(j)的最少取得数量,由于我们只需要关键点(就是那些要求的珠子)的(dis),因此对于每个关键点(bfs)一发即可求出(dis)

    由于(k)非常的小,可以用状压(dp),设(f(i,S))表示选了(i)个珠子集合状态为(S)的最小价值,考虑转移时枚举最后一个珠子和倒数第二个珠子。

    但是这样做是有问题的,比如说我们现在有(4)个珠子,枚举最后一个珠子是(3),而倒数第二个珠子是(2),那么转移就是从(f(3,(1011)_2)+dis(2,3))转移过来的,但是问题在于:(f(3,(1011)_2))有可能最后一个取得不是(2),那么我们就歇逼了。

    那考虑直接再加一维表示最后一个取的珠子,即(f(i,S,j))表示取了(i)个珠子,关键点集合状态为(S),最后一个取的珠子是(j),转移直接枚举最后两个取的即可。

    答案直接枚举最后一个取的珠子即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<queue>
    #define N 100005
    #define MAXN 18
    #define pb push_back
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int n,m,k,f[18][1<<18][18],C[N],dis[18][N],vis[N];
    vector<int>G[N];
    void bfs(int S)
    {
    	queue<int>q;
    	memset(vis,0,sizeof(vis));
    	vis[C[S]]=1;
    	dis[S][C[S]]=0;
    	q.push(C[S]);
    	while(!q.empty())
    	{
    		int x=q.front();q.pop();int siz=G[x].size();
    		for(int i=0;i<siz;i++)
    		{
    			if(!vis[G[x][i]])
    			{
    				dis[S][G[x][i]]=dis[S][x]+1;
    				vis[G[x][i]]=1;
    				q.push(G[x][i]);
    			}
    		}
    	}
    }
    int main()
    {
    	n=read();m=read();
    	for(int i=1;i<=m;i++)
    	{
    		int x=read(),y=read();
    		G[x].pb(y);G[y].pb(x);
    	}
    	k=read();
    	for(int i=1;i<=k;i++)C[i]=read();
    	memset(dis,0x3f,sizeof(dis));
    	for(int i=1;i<=k;i++)bfs(i);
    	memset(f,0x3f,sizeof(f));
    	for(int i=1;i<=k;i++)f[1][1<<(i-1)][i]=1;
    	for(int i=2;i<=k;i++)
    	{
    		for(int S=0;S<(1<<k);S++)
    		{
    			for(int j=1;j<=k;j++)
    			{
    				if(!(S&(1<<(j-1))))continue;
    				for(int l=1;l<=k;l++)
    				{
    					if(!(S&(1<<(l-1))))continue;
    					f[i][S][j]=min(f[i][S][j],f[i-1][S-(1<<(j-1))][l]+dis[j][C[l]]);
    				}
    			}
    		}
    	}
    	int ans=0x3f3f3f3f;
    	for(int i=1;i<=k;i++)
    	{
    		ans=min(ans,f[k][(1<<k)-1][i]);
    	}
    	printf("%d
    ",ans==0x3f3f3f3f?-1:ans);
    	return 0;
    }
    

    F - Shift and Inversions

    题意:一个排列(a),定义一个(a)的置换(b)(b_i = a_{i+k mod N}),求对于每一个(kin[0,N-1]),所对应的(b)的逆序对数量。

    说实话没E题难。

    首先这个(b)就是每一次把(a)数组的第一个数取出来放到最后一个。

    为了方便,我们先把(a)中所有数都加(1),让它变成一个排列,方便操作。

    那么考虑当前第一个数为(x),把他扔到最后一个会有怎样的影响呢?

    首先因为第一个数为(x),那么(1 o x-1)中所有数一定都在第一个的后边(废话),因此扔到后边逆序对数会减少(x-1),但同时因为比(x)大的数也都在后边,那会多出来(n-x)对逆序对。

    因此只需要处理(k=0)的情况,之后依次看第一个数即可。

    静态序列的逆序对数量是个经典题,树状数组解决即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define lowbit(x) x&-x
    #define N 300005
    #define int long long
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int n,a[N],ans;
    struct BIT
    {
    	int c[N];
    	void modify(int x,int k){for(;x<=n;x+=lowbit(x))c[x]+=k;}
    	int query(int x){int res=0;for(;x;x-=lowbit(x))res+=c[x];return res;}
    }T;
    signed main()
    {
    	n=read();
    	for(int i=1;i<=n;i++)a[i]=read()+1;
    	for(int i=1;i<=n;i++)
    	{
    		ans+=i-1-T.query(a[i]);
    		T.modify(a[i],1);
    	}
    	for(int i=1;i<=n;i++)
    	{
    		printf("%lld
    ",ans);
    		ans-=(a[i]-1);ans+=n-a[i];
    	}
    }
    

    感觉不是非常难,下次vp一下ARC。

  • 相关阅读:
    Python:完全数
    Python:将 list 写入一个 txt 文件
    Python:对称数组
    Python:列表反转、切片
    Python:print输出间隔,换行
    Python:打印99乘法表
    Python:排序(sort / 冒泡排序)
    安装pipenv
    flex布局
    python正则表达式
  • 原文地址:https://www.cnblogs.com/szmssf/p/14394682.html
Copyright © 2020-2023  润新知