Codeforces Round 555 div.3

A. Reachable Numbers:

给定操作,问最多表示几个数。找规律。

代码:

#include <bits/stdc++.h>
using namespace std;


int main(){
	int n;
	scanf("%d",&n);
	int cnt=0;
	while(1){
		if(n<=9){cnt+=9;break;}
		else{
			n+=1;
			while(!(n%10))n/=10;
			cnt++;
		}
	}
	printf("%d\n",cnt);
	return 0;
}

B. Long Number:

贪心,从最高位开始比对,遇到映射比原数更大的情况就开始把原数据变为映射,直到遇到映射比原数更小的情况。注意不要把strlen()函数写在for循环判断上,会从On的时间复杂度变为On^2,造成TLE。

代码:

#include <bits/stdc++.h>
using namespace std;

char s[200005];
int n;
int f[10];
int main(){
	scanf("%d",&n);
	getchar();
	scanf("%s",s);
	bool flag=1;
	for(int i=1;i<=9;i++)scanf("%d",&f[i]);
	int len=strlen(s);
	for(int i=0;i<len;i++){
		if(f[s[i]-'0']>s[i]-'0'){
			s[i]=f[s[i]-'0']+'0';
			flag=0;
		}
		else if(f[s[i]-'0']<s[i]-'0'&&!flag)
			break;
	}
	printf("%s\n",s);
	return 0;
}

C1. Increasing Subsequence (easy version):

题意:给一个n个数的序列且这n个数两两不相同,从两端选取一个数拿出序列组成一个新的序列,一次操作只能拿一个,要使新序列为递增序列且长度最长,输出最长长度和每次操作取左取右的选择。

思路:贪心,若两端都能连接到新序列末则选小的,若只有一端能则只能选那一端,若都不能选则跳出循环,操作终止。

代码:

#include <bits/stdc++.h>
using namespace std;

int n;
int a[200005];
int cnt;
int x[200005];
int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++)scanf("%d",&a[i]);
	int l=0,r=n-1,t=0;
	while(l<=r){
		if(a[l]<a[r]&&a[l]>t){
			x[cnt++]=0;
			t=a[l++];
		}
		else if(a[r]<a[l]&&a[r]>t){
			x[cnt++]=1;
			t=a[r--];
		}
		else if(a[l]>t&&a[r]<t){
			x[cnt++]=0;
			t=a[l++];
		}
		else if(a[l]<t&&a[r]>t){
			x[cnt++]=1;
			t=a[r--];
		}
		else if(r==l&&a[l]>t){
			x[cnt++]=0;
			break;
		}
		else if(a[l]<t&&a[r]<t)
			break;
	}
	printf("%d\n",cnt);
	for(int i=0;i<cnt;i++){
		if(x[i]==0)printf("L");
		else printf("R");
	}
	return 0;
}

C2. Increasing Subsequence (hard version):

在C1的基础上改一下判定条件,加入对左右元素相等情况的特判就可以了。

#include <bits/stdc++.h>
using namespace std;

int n;
int a[200005];
int cnt;
int x[200005];
int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++)scanf("%d",&a[i]);
	int l=0,r=n-1,t=0;
	while(l<=r){
		if(a[l]<a[r]&&a[l]>t){
			x[cnt++]=0;
			t=a[l++];
		}
		else if(a[r]<a[l]&&a[r]>t){
			x[cnt++]=1;
			t=a[r--];
		}
		else if(a[l]>t&&a[r]<=t){
			x[cnt++]=0;
			t=a[l++];
		}
		else if(a[l]<=t&&a[r]>t){
			x[cnt++]=1;
			t=a[r--];
		}
		else if(r==l&&a[l]>t){
			x[cnt++]=1;
			break;
		}
		else if(a[l]==a[r]&&a[l]>t){
			int pos=1;
			int ll=l+1,rr=r-1,tt=a[l];
			while(a[ll]==a[rr]&&a[ll]>tt&&ll<=rr){
				pos++;
				tt=a[ll];
				ll++;
				rr--;
			}
			if(a[ll]<=tt&&a[rr]>tt&&ll<rr){
				int pos1=0;
				int rrr=rr;
				if(a[rrr]>tt)pos1=1;
				while(a[rrr]<a[rrr-1]&&rrr>ll){
					pos1++;
					rrr--;
				}
				pos+=pos1;
				for(int i=0;i<pos;i++){
					x[cnt++]=1;
				}
				break;
			}
			else if(a[ll]>tt&&a[rr]<=tt&&ll<rr){
				int pos1=0;
				int lll=ll;
				if(a[lll]>tt)pos1=1;
				while(a[lll]<a[lll+1]&&lll<rr){
					pos1++;
					lll++;
				}
				pos+=pos1;
				for(int i=0;i<pos;i++){
					x[cnt++]=0;
				}
				break;
			}
			else if(a[ll]>tt&&a[rr]>tt&&ll<rr){
				int pos1=0,pos2=0;
				int rrr=rr;
				if(a[rrr]>tt)pos1=1;
				while(a[rrr]<a[rrr-1]&&rrr>ll){
					pos1++;
					rrr--;
				}
				int lll=ll;
				if(a[lll]>tt)pos2=1;
				while(a[lll]<a[lll+1]&&lll<rr){
					pos2++;
					lll++;
				}
				if(pos1>pos2)for(int i=0;i<pos1+pos;i++)x[cnt++]=1;
				else for(int i=0;i<pos+pos2;i++)x[cnt++]=0;
				break;
			}
			else{
				for(int i=0;i<pos;i++)x[cnt++]=1;
				break;
			}
		}
		else if(a[l]<=t&&a[r]<=t)
			break;
	}
	printf("%d\n",cnt);
	for(int i=0;i<cnt;i++){
		if(x[i]==0)printf("L");
		else printf("R");
	}
	return 0;
}

E. Minimum Array:

贪心思路,从n-a[i]开始找,由于n-a[i]一直找到n-1,(n-1+a)%n=a-1可知,这样找一定是模最小的。
如果找不到,再从0开始找到n-a[i]。不能选用下标计数,线性查找n^2必定会tle,选用multiset储存b每次用lower_bound进行二分搜索可以把复杂度降为nlogn。

代码:

#include <bits/stdc++.h>
using namespace std;

int n;
int a[200005];
multiset<int>b;
int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++)scanf("%d",&a[i]);
	for(int i=0;i<n;i++){
		int t;
		scanf("%d",&t);
		b.insert(t);
	}
	multiset<int>::iterator it;
	for(int i=0;i<n;i++){
		it=b.lower_bound(n-a[i]);
		if(it==b.end())it=b.begin();
		a[i]=(a[i]+*it)%n;
		b.erase(it);
	}
	for(int i=0;i<n;i++)printf("%d ",a[i]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值