Codeforces Round #201(Div.2)

https://codeforces.com/contest/347
ZR的作业,来填填坑

A. Difference Row
睿智题,贪心最后面的最大,最前面的最小,中间排序就行了

// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() puts("okkkkkkkk")
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;
#define int LL

const int inf = 1 << 30;
const int maxn=11111;

int n;
int a[maxn],t[maxn];
int mn=inf,mx=-inf;

signed main(){
	scanf("%I64d",&n);for(int i=1;i<=n;i++)scanf("%I64d",&a[i]),mn=min(mn,a[i]),mx=max(mx,a[i]);
	if(n==1){printf("%I64d\n",a[1]);return 0;} 
	int ccc,cd;
	for(int i=1;i<=n;i++){
		if(mn==a[i])t[n]=a[i],ccc=i;
		if(mx==a[i])t[1]=a[i],cd=i;
	}
	int cc=1;
	for(int i=1;i<=n;i++){
		if(ccc!=i&&cd!=i)t[++cc]=a[i];
	}
	sort(t+2,t+n);
	for(int i=1;i<=n;i++)printf("%I64d ",t[i]);

	return 0;
}

B. Fixed Points
睿智题,注意到答案是 p [ i ] = = i p[i]==i p[i]==i 的数的个数+ d d d 0 ≤ d ≤ 2 0\le d\le 2 0d2,看是否存在 p [ p [ i ] ] = = i p[p[i]]==i p[p[i]]==i的情况即可

// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() puts("okkkkkkkk")
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1 << 30;
const int maxn=2e5+5;

int n;
int a[maxn];

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]),++a[i];
	int ans=0,mx=0;
	for(int i=1;i<=n;i++){
		if(a[i]==i){++ans;continue;}
		if(mx==2)continue;
		if(a[a[i]]==i){mx=2;continue;}
		else mx=1;
	}
	printf("%d\n",ans+mx);

	return 0;
}

C. Alice and Bob
注意最终情况就是形成了一个等差数列
发现操作特别像辗转相减的过程,大胆猜测最终最小的那个数一定是gcd{a[i]}
根据辗转相除的结论,最终 set 里面所有的数一定都是 gcd{a[i]} 的倍数,这就有了公差
因此可以根据a[i] 中最大的数算出项数,-n (set里面本来就有n个数) 看奇偶性即可
项数就是要到达输的状态的次数

// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() puts("okkkkkkkk")
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1 << 30;

int gcd(int a,int b){return !b?a:gcd(b,a%b);}

int n;
int a[111111];

int main(){
	int gd=0,mx=0; 
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]),gd=gcd(gd,a[i]),mx=max(mx,a[i]); 
	int xs=(mx-gd)/gd+1-n;
	if(xs&1)puts("Alice");
	else puts("Bob"); 

	return 0;
}

D. Lucky Common Subsequence
辣鸡dp,毁我青春
这题状态和前两个转移都非常好考虑,主要在于第三个
d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示考虑到 A [ 1.. i ] , B [ 1.. j ] A[1..i], B[1..j] A[1..i],B[1..j]的公共子序列与 v i r u s [ 1.. k ] virus[1..k] virus[1..k]相同时长度的最大值
d p [ i + 1 ] [ j ] [ k ] = m a x { d p [ i + 1 ] [ j ] [ k ] ,   d p [ i ] [ j ] [ k ] } dp[i+1][j][k]=max\{ dp[i+1][j][k], \ dp[i][j][k] \} dp[i+1][j][k]=max{dp[i+1][j][k], dp[i][j][k]}
d p [ i ] [ j + 1 ] [ k ] = m a x { d p [ i ] [ j + 1 ] [ k ] ,   d p [ i ] [ j ] [ k ] } dp[i][j+1][k]=max\{ dp[i][j+1][k], \ dp[i][j][k] \} dp[i][j+1][k]=max{dp[i][j+1][k], dp[i][j][k]}
d p [ i + 1 ] [ j + 1 ] [ w ] = m a x { d p [ i + 1 ] [ j + 1 ] [ w ] ,   d p [ i ] [ j ] [ k ] } dp[i+1][j+1][w]=max\{ dp[i+1][j+1][w], \ dp[i][j][k] \} dp[i+1][j+1][w]=max{dp[i+1][j+1][w], dp[i][j][k]},其中 w w w就是匹配到的 C C C的位置
然后记录一下每个转移到的位置,最后dfs一下就可以啦

代码:

// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() puts("okkkkkkkk")
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1 << 30;
const int maxn=111;

struct data{int x,y,z;}pre[maxn][maxn][maxn],e; 
char a[maxn],b[maxn],c[maxn];
int dp[maxn][maxn][maxn],nxt[maxn];
int na,nb,nc;

void getnx(){
	nxt[0]=0;
	
	int j=0;
	for(int i=1;i<nc;i++){
		for(;c[j]!=c[i]&&j>0;j=nxt[j-1]);
		if(c[j]==c[i])++j;
		nxt[i]=j;
	}
}

void dfs(data cur){
	int cx=cur.x,cy=cur.y,cz=cur.z;
	if(cx==cy&&cy==cz&&cz==0)return ;
	
	data ch=pre[cx][cy][cz];
	dfs(ch);
	
	int hx=ch.x,hy=ch.y,hz=ch.z;
	if(dp[hx][hy][hz]+1==dp[cx][cy][cz])printf("%c",a[hx]);
}

int main(){
	scanf("%s",a);scanf("%s",b);scanf("%s",c);
	memset(dp,0,sizeof dp);
	na=strlen(a);nb=strlen(b);nc=strlen(c);
	getnx();
	for(int i=0;i<=na;i++)for(int j=0;j<=nb;j++)dp[i][j][0]=0;
	for(int i=0;i<=na;i++){
		for(int j=0;j<=nb;j++){
			for(int k=0;k<nc;k++){
				if(dp[i+1][j][k]<dp[i][j][k]){
					dp[i+1][j][k]=dp[i][j][k];
					pre[i+1][j][k].x=i;
					pre[i+1][j][k].y=j;
					pre[i+1][j][k].z=k;
				}
				
				if(dp[i][j+1][k]<dp[i][j][k]){
					dp[i][j+1][k]=dp[i][j][k];
					pre[i][j+1][k].x=i;
					pre[i][j+1][k].y=j;
					pre[i][j+1][k].z=k;
				}
				
				if(a[i]==b[j]){
					int w=k;
					//**********
					for(;a[i]!=c[w]&&w>0;w=nxt[w-1]);
					if(a[i]==c[w])++w;
					else w=0;
					//**********
					
					if(dp[i+1][j+1][w]<dp[i][j][k]+1){
						dp[i+1][j+1][w]=dp[i][j][k]+1;
						pre[i+1][j+1][w].x=i;
						pre[i+1][j+1][w].y=j;
						pre[i+1][j+1][w].z=k;
					}
				}
//				printf("%d \n",dp[i][j][k]);
			}
		}
	}
	
	int mx=0;
	for(int k=0;k<nc;k++){
		if(dp[na][nb][k]>mx){
			mx=dp[na][nb][k];
			e.x=na;e.y=nb;e.z=k;
		}
	}
	if(mx==0)return puts("0"),0;
	dfs(e);

	return 0;
}

E. Number Transformation II
比D简单
贪心一下,每次加到set里面就行了

// by Balloons
#include <cstdio>
#include <set>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() puts("okkkkkkkk")
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1 << 30;

set<int>S;
int n;

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int x;
		scanf("%d",&x);
		S.insert(x);
	}
	int ans=0,a,b;scanf("%d%d",&a,&b);
	while(a>b){
		set<int>T=S;
		int tmpa=a-1;
//		if(S.empty())debug();
		for(set<int>::iterator it = S.begin(); it != S.end(); it ++ ){
			int x=*it;
//			printf("FF %d %d\n",a-a%x,S.size());
			if(a-a%x<b)T.erase(x);
			else tmpa=min(tmpa,a-a%x);
			if(S.empty())break;
		}
		ans++;
		a=tmpa;
		S=T;
//		printf("%d\n",a);
	}
	printf("%d\n",ans);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值