大一第二次周训题解

大一第二次周训

题好像都是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;
}

第一次写题解,如有错误或者能改进的地方多多指正。

发布了34 篇原创文章 · 获赞 7 · 访问量 1903

猜你喜欢

转载自blog.csdn.net/qq_43628761/article/details/90138745