Codeforces Round 863 (Div. 3)

题解报告

基本的一些理解和问题都在注释中
A:Insert Digit
找到第一个小于输入数字的数的位置塞进去就好了,可以细推,但是粗略想想也能知道

#include <bits/stdc++.h>
using namespace std;
int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T;cin>>T;
    while(T--)
    {
        string s;
        int len,num;
        cin>>len>>num>>s;
        int flag=1;
        for(int i=0;i<len;i++)//遇到第一个小的就输出,等于的不行。一定等于的话不一定是最优秀的,
        {
            if(flag&&s[i]-'0'<num)cout<<num,flag=0;
            cout<<s[i];
        }
        if(flag)cout<<num;
        cout<<endl;
    }
    return 0;
}

B:Conveyor Belts
考虑离中间点的距离大的,然后判断各个点位在第几层,判断层数的距离就行了
注意离中间点的距离的计算就行了

#include <bits/stdc++.h>
using namespace std;
int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T;cin>>T;
    while(T--)
    {
        int N,X1,Y1,X2,Y2;
        cin>>N>>X1>>Y1>>X2>>Y2;
        N=N/2;
        int DX1=N-X1;if(DX1<0)DX1=-DX1-1;
        int DY1=N-Y1;if(DY1<0)DY1=-DY1-1;
        int DX2=N-X2;if(DX2<0)DX2=-DX2-1;
        int DY2=N-Y2;if(DY2<0)DY2=-DY2-1;
        cout<<(int)abs(max(DX1,DY1)-max(DX2,DY2))<<endl;
    }
    return 0;
}

C:Restore the Array
这道题目既可以通过找规律,也可以通过模拟来进行构造
不过我没有写出来,菜是原罪,哎~~
画图!!!画图!!!画图!!!画图看关系是真的很重要

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int num[maxn];
// int main(void)//方法一:不怎么好想
// {
//     ios::sync_with_stdio(false);
//     cin.tie(0);cout.tie(0);
//     int T;cin>>T;
//     while(T--)//取两个的间隔的max组成的数组是不可能存在(小-大-小)这种结构的,所以
//     {//在两个数中每次取小的,就可以在原数组的推导中每次都可以通过取大的取出那个数,因为一个数不是比右边的大,就是比左边的大,或者相等。
//         //一个数不可能同时比两边的大,所以这种方法一定可以按照顺序把每个数都取一遍。
//         //对于边界的值,如果直接放上B数组的边界,这样就可以保证所有的数都可以取到,
//         //边界的值可以放B数组边界的值,这样就可以保证不管是先取还是后取,都会有第一个数和最后一个数。
//         int N;cin>>N;
//         for(int i=0;i<N-1;i++)cin>>num[i];
//         cout<<num[0]<<' ';
//         for(int i=0;i<N-2;i++)cout<<min(num[i],num[i+1])<<' ';
//         cout<<num[N-2]<<endl;
//     }
//     return 0;
// }
int main(void)
{
    ios::sync_with_stdio(false);//比较容易想到
    cin.tie(0);cout.tie(0);
    int T;cin>>T;
    while(T--)
    {
        //不断的塞入数组进行模拟
        int N;cin>>N;
        for(int i=0;i<N-1;i++)cin>>num[i];
        vector<int> ans;
        ans.push_back(num[0]);
        int cnt=1;
        for(int i=1;i<N-1;i++)
        {
            if(cnt==i){//决定别人的时候
                if(ans.back()<num[i])cnt++,ans.push_back(0);
                ans.push_back(num[i]);
                cnt++;
            }else{//决定自己的时候
                if(ans.back()<num[i])cnt++,ans.push_back(num[i]);
            }
        }
        if(ans.size()!=N)ans.push_back(0);
        for(int i=0;i<N;i++)cout<<ans[i]<<' ';
        cout<<endl;
    }
    return 0;
}

D:Umka and a Long Flight
想像每增加一个正方形后,长度为1的正方形可以怎么变换就行了
长度为1的正方形可以怎么位移?水平方向上的移动是怎么样的,可以怎么移动?竖直方向是怎么样的?

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=50;
ll Fib[maxn];
void init()
{
    Fib[0]=1;Fib[1]=1;
    for(int i=2;i<maxn;i++)
        Fib[i]=Fib[i-1]+Fib[i-2];
}
int main(void)
{
    int T;cin>>T;
    init();
    while(T--)
    {
        ll N,X,Y;
        cin>>N>>X>>Y;
        int flag=N&1;
        for(int i=N;i>=1;i--)if((i&1)!=flag&&X-Fib[i]>=1)X-=Fib[i];
        for(int i=N;i>=1;i--)if((i&1)==flag&&Y-Fib[i]>=1)Y-=Fib[i];
        if(X==1&&Y==1)cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

E:Living Sequence
去掉一个数后就是九进制数,考虑每个数的组成后拆分就行了

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main(void)
{
    int T;cin>>T;
    while(T--)//就是个十进制化为九进制而已
    {
        ll N;cin>>N;
        ll ans=0,cnt=0;
        while(N)
        {
            ans+=pow(10,cnt)*((N%9)>=4?((N%9)+1):(N%9));
            N/=9;
            cnt++;
        }
        cout<<ans<<endl;
    }
    return 0;
}

G1:Vlad and the Nice Paths (easy version)
线性dp时,考虑自己这个位置是怎么被处理的,从操作的角度来考虑,既可以被除去,也能成为一部分
多多画图,看看状态之间是怎么转移的,各种操作会导致怎么样的状态

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e2+10;
const int MOD=1e9+7;
int dp[maxn][maxn];//当前位置,有j个长度为K的序列的个数。
int C[maxn][maxn];
int num[maxn];
void init()//获取组合数的经典递推
{
    for(int i=0;i<maxn;i++)
    {
        C[0][i]=1;
        for(int j=1;j<=i;j++)
            C[j][i]=(C[j-1][i-1]+C[j][i-1])%MOD;
    }
}
int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    init();
    int T;cin>>T;
    while(T--)
    {
        memset(dp,0,sizeof(dp));
        int N,K;cin>>N>>K;
        for(int i=1;i<=N;i++)cin>>num[i];
        if(K==1)//注意这里后面利用到了组合数,所以这里要先特判一下
        {
            cout<<1<<endl;
            continue;
        }
        dp[0][0]=1;
        for(int i=1;i<=N;i++)
        {
            dp[i][0]=1;
            for(int j=1;j<=N/K+1;j++)//对所有的情况进行更新。
            {
                int now=1;
                 for(int k=i-1;k>=1;k--)//枚举如果num[i]作为新的K位的时候的所有的可能性。
                {
                    if(num[k]==num[i])//利用组合算进行统计。
                    {
                        now++;
                        if(now>=K)dp[i][j]=(dp[i][j]+(1LL*dp[k-1][j-1]*C[K-2][now-2])%MOD)%MOD;
                    }
                }
                dp[i][j]=(dp[i][j]+dp[i-1][j])%MOD;//如果num[i]这位不算,那么它的可能就是前面的可能,这里要加上
            }
        }
        for(int i=N/K+1;i>=0;i--)//从长度最大的开始枚举。
        {
            if(dp[N][i])
            {
                cout<<dp[N][i]<<endl;
                break;
            }
        }
    }
    return 0;
}

G2:Vlad and the Nice Paths (hard version)
由于不需要每个长度的,所以只要记录最长的就行了,每次对最长的进行更新

#include <bits/stdc++.h>
using namespace std;
const int maxn=5e3+10;
const int MOD=1e9+7;
int dp[maxn],Max[maxn],num[maxn];//dp记录这个位置i前(包括这个位置i)长度为Max[i]的情况的个数,
//Max[i]记录这里可以有的满足题目条件的最长的分区数。
//num记录原数组
int C[maxn][maxn];
void init()
{
    for(int i=0;i<maxn;i++)
    {
        C[0][i]=1;
        for(int j=1;j<=i;j++)
            C[j][i]=(C[j-1][i-1]+C[j][i-1])%MOD;
    }
}
int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    init();
    int T;cin>>T;
    while(T--)
    {
        memset(dp,0,sizeof(dp));
        memset(Max,0,sizeof(Max));
        int N,K;cin>>N>>K;
        for(int i=1;i<=N;i++)cin>>num[i];
        dp[0]=1;
        for(int i=1;i<=N;i++)
        {
            int now=1;
            for(int j=i-1;j>=1;j--)//num[i]作为dp[i]的最后一个的情况。
            {
                if(num[i]==num[j])
                {
                    now++;
                    if(now==K)Max[i]=Max[j-1]+1;//可以扩充的最长的
                    if(now>=K)
                    {
                        if(Max[i]!=Max[j-1]+1)break;//不是最长的了
                        dp[i]=(dp[i]+(1LL*dp[j-1]*C[K-2][now-2])%MOD)%MOD;
                    }
                }
            }
            //证明i之前最长的不是i开始的,所以i这里的组合不是要的,置为0
            if(Max[i]<Max[i-1])
            {
                dp[i]=0;
                Max[i]=Max[i-1];
            }
            //i可以继承i-1的集合,所以直接加上dp[i-1]的情况。
            //不作为最后一个考虑的情况。
            if(Max[i]==Max[i-1])dp[i]=(dp[i]+dp[i-1])%MOD;
        }
        cout<<dp[N]<<endl;
    }
    return 0;
}

F不太会,就不写了
掉分了,失败的一场比赛,哎~~

posted @ 2023-04-10 12:55  WUTONGHUA02  阅读(71)  评论(0编辑  收藏  举报