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;
}