大一第二次周训
题好像都是codeforces上的题,最近的div3
A - Reachable Numbers(codeforces 1157A)
题意:给你一个数n(1≤n≤109),每次可以对这个数+1,加完后如果这个数有后缀0就可以把这个0去掉,就可以生成一个新的数。问最后能得到几个不同的数。经过手动模拟后发现最后这个数只能变成个位数(1~9)并且在这九个数上循环。
#include <iostream>
#include <algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1e4;
long long num[maxn];
int main()
{
long long n,ans=0;
scanf("%lld",&n);
if(n%10==0){//特判输入的n有没有后缀0.如果有的话去掉后缀0
ans+=10;
n=n/10+1;
}
while(n>=10){//判断n是不是个位数
while(n%10!=0){//判断n没有后缀0,n依次加1
ans++;
n++;
}
while(n%10==0)n/=10;//可能有多个后缀0
}
ans+=9;//加上个位数的个数.
printf("%lld\n",ans);
return 0;
}
B - Zoning Restrictions Again (codeforces 1162A)
题意:有一段街区要造房子,有n个点(编号1~n)如果房子的高度是a,那么就可以从这个房子获取a2的利益。但是会有m次限高,每给一次限高条件会有三个数x,y,z表示从x号房到y号房的高度不能超过z。问能获得最大的利益是多少(每个房子的初始限高是h)(1≤n,h,m≤50),数据不大直接bruteforce,思路:先用一个数组来存初始高度h,然后m次循环更新从x号房到y号房的高度为z(注意每次的限高是有效的,也就是说假如有一次限高条件将a号房更新为1,如果之后的限高条件包含a,且把限高增大了,那么我们就不能把a号房高度更新)
#include <iostream>
#include <algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<set>
#include<vector>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=60;
long long num[maxn];
int main()
{
int n,h,m;
scanf("%d%d%d",&n,&h,&m);
for(int i=1;i<=n;i++)num[i]=h;
while(m--){
int a,b,x;
scanf("%d%d%d",&a,&b,&x);
for(int i=a;i<=b;i++)
if(x<num[i])num[i]=x;//这里需要注意
}
long long ans=0;
for(int i=1;i<=n;i++)ans+=num[i]*num[i];
printf("%lld\n",ans);
return 0;
}
C - Stock Arbitraging(不知道是cf上的哪个题…)
题意:
小明是个狡诈的商人早上要买东西(早上他身上没有任何商品,所以他要去买,然后晚上卖了赚差价…),他有金钱r,早市有。。。哎呀不想写题意了。。。
这道题的传送门
#include <iostream>
#include <algorithm>
#include<cstdio>
#include<cmath>
#include<string>
#include<string.h>
#include<queue>
#include<set>
#include<vector>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=50;
int s1[maxn],s2[maxn];
int main()
{
int n,m,r;
scanf("%d%d%d",&n,&m,&r);
for(int i=0;i<n;i++)scanf("%d",&s1[i]);
for(int i=0;i<m;i++)scanf("%d",&s2[i]);
sort(s1,s1+n);
sort(s2,s2+m);
if(s1[0]>=s2[m-1]){
printf("%d\n",r);//如果他能卖的价钱还没有他买的价钱高,那就不用买了,这样能获得的钱最多
}
else {
int cnt=r/s1[0];
int ans=r-cnt*s1[0]+cnt*s2[m-1];
printf("%d\n",ans);
}
return 0;
}
D - Long Number (codeforces1157B)
题意:有一个数n(1≤n≤2⋅105),You can perform the following operation no more than once: choose a non-empty contiguous subsegment of digits in a, and replace each digit x from this segment with f(x). For example, if a=1337, f(1)=1, f(3)=5, f(7)=3, and you choose the segment consisting of three rightmost digits, you get 1553 as the result.
注意只能进行一次操作,这一次操作可以改变多个数,但这多个数必须来是连续的子序列,问通过这次操作能得到的做大的数是多少。思路:贪心,优先改变高位的值,找到了一个大于原数的位置后从这个位置起继续改变,如果遇到了小于原数的位置,就终止改变。
#include <iostream>
#include <algorithm>
#include<cstdio>
#include<cmath>
#include<string>
#include<string.h>
#include<queue>
#include<set>
#include<vector>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=2e5+10;
char str[maxn];
int num[maxn];
int mp[11];
int main()
{
int n;
scanf("%d",&n);
getchar();
scanf("%s",str);
int x;
for(int i=1;i<=9;i++){
scanf("%d",&x);
mp[i]=x;
}
int len=strlen(str);
for(int i=0;i<len;i++)
if(mp[str[i]-'0']>str[i]-'0'){
while(i<len&&mp[str[i]-'0']>=str[i]-'0'){//要加等号,如果不加就WA...
str[i]=mp[str[i]-'0']+'0';
i++;
}
break;
}
printf("%s\n",str);
return 0;
}
E - Increasing Subsequence (easy version)(codeforces 1157C1)
题意:
给你一个序列,这个序列有n个数(1≤n≤2⋅105),每个数都不超过n,且每个数都不一样,每次可以从两端取出一个数,组成一个新的序列,问能得到一个严格递增的序列的最大长度是多少,并且要输出操作过程。
思路:
模拟一遍,首先用两个“指针”left和right来指向数组的两端,再用一个中转变量t来存每次取出的数,如果a[l]<a[r],又if(a[l]>t),则t=a[l],l++,else if(a[r]>t),t=a[r],r–;另一种情况也差不多这样。
n最大2⋅105 直接暴力,O(n)
#include<bits/stdc++.h>
using namespace std;
int main()
{
char str[200005]= { };
int n,a[200005]= { },l,r,t=0,k=0,i,m=0;
scanf("%d",&n);
for(i=0; i<n; i++)
scanf("%d",&a[i]);
for(l=0,r=n-1; l<=r;)
{
if(a[l]>a[r])
{
if(a[r]>t)
{
t=a[r];
m++;
str[k++]='R';
r--;
}
else if(a[l]>t)
{
m++;
t=a[l];
str[k++]='L';
l++;
}
else
break;
}
else if(a[l]<a[r])
{
if(a[l]>t)
{
m++;
t=a[l];
str[k++]='L';
l++;
}
else if(a[r]>t)
{
m++;
t=a[r];
str[k++]='R';
r--;
}
else
break;
}
if(r==l)//特判l==r的情况,不能写成if(l==r&&a[l]>t)
{
if(a[l]>t){
m++;
str[k++]='L';
}
break;
}
}
printf("%d\n",m);
printf("%s\n",str);
return 0;
}
还有一种更简单的方法:思想:因为每个数都不一样且最大的数不超过N,
最好情况的长度就是N,所以我们就可以用一个循环(i=1;i<=n;i++)
每次从两端的元素中找i,如果左边找到了i,l++;
如果右边找到了i,r–;两边都没找到就continue找下一个i;
#include <iostream>
#include <algorithm>
#include<cstdio>
#include<cmath>
#include<string>
#include<string.h>
#include<queue>
#include<set>
#include<vector>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=2e5+10;
int num[maxn];
string str;
int cnt;
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
int left=1,right=n;
for(int i=1;i<=n&&left<=right;i++){
if(num[left]==i)
str+='L', left++, cnt++;
else if(num[right]==i)
str+='R', right--, cnt++;
}
cout<<cnt<<endl<<str<<endl;
return 0;
}
F - Increasing Subsequence (hard version)(codeforces 1157C2)
题意和上一题擦不多,不一样的就是每个数有可能相同,且有可能超过n,只能乖乖的模拟一遍,注意两边相同的情况:如果选了一边就只能一直走那一边。这样就看那边更长一些就好。
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
string str;
const int maxn=2e5+10;
int a[maxn];
int left(int l,int r,int ans)
{
int sum=1;
for(int i=l+1;i<=r;i++){
if(a[i]>ans)
{
ans=a[i];
sum++;
}
else break;//这里要注意下,因为没写break WA了几次......
}
return sum;
}
int right(int l,int r,int ans)
{
int sum=1;
for(int i=r-1;i>=l;i--){
if(a[i]>ans)
{
ans=a[i];
sum++;
}
else break;
}
return sum;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
int l=1,r=n;
int ans=0;
while(l<=r)
{
if(a[l]<a[r])
{
if(a[l]>ans)
{
ans=a[l];
str+='L';
l++;
}
else if(a[r]>ans)
{
ans=a[r];
str+='R';
r--;
}
else break;
}
else if(a[l]>a[r])
{
if(a[r]>ans)
{
ans=a[r];
str+='R';
r--;
}
else if(a[l]>ans)
{
ans=a[l];
str+='L';
l++;
}
else break;
}
else if(a[l]==a[r])
{
if(a[l]<ans)break;
ans=a[l];
int cnt1=left(l,r,ans);
int cnt2=right(l,r,ans);
if(cnt1>=cnt2)
str.append(cnt1,'L');
else
str.append(cnt2,'R');
break;
}
}
printf("%d\n",str.size());
cout<<str<<endl;
return 0;
}
G - Minimum Array(codeforces 1157E)
题意:
给你一个a序列和b序列(长度为n),你可以任意改变b序列的顺序,然后你需要生成一个c序列,c[i]=(a[i]+b[i])%n,问字典序最小的c序列是什么。
思路:
用multiset,可以自动排序且不去重,如过要删除一个元素那么所有的这个元素都删除。二分思想(s.lower_bound(x))。
#include<stdio.h>
#include<iostream>
#include<string>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=2e5+10;
long long a[maxn],b[maxn],c[maxn];
multiset<long long >s;
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lld",&a[i]);
for(int i=0;i<n;i++){
scanf("%lld",&b[i]);//没必要用b数组
s.insert(b[i]);
}
for(int i=0;i<n;i++)
{
long long ans=n-a[i];
auto it=s.lower_bound(ans);
if(it==s.end())//没找到的话,就找s里的第一个元素这样取余n后的数就小
it=s.begin();
c[i]=((*it)+a[i])%n;
s.erase(it);
}
for(int i=0;i<n;i++)
printf("%lld%c",c[i],i==n-1?'\n':32);
return 0;
}
第一次写题解,如有错误或者能改进的地方多多指正。