A. Dreamoon and Ranking Collection
A题大家应该都没啥问题叭QAQ 题意就是已经比赛了n场 n场的场次都已经告诉了你 问你再比x次 问你你最大的名次是多少(这个最大的名次是指 1-当前名次都已经拿过了)然后注意数据范围 n,x<=100 所以最多可以到两百名呢 所以记得数组要开200多一点
(呜呜我的代码日常很长 所以手速很慢

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
    int t;
    cin>>t;
    while (t--){
        int n,x;
        scanf("%d%d",&n,&x);
        int a[105];
        int visit[205]={0};
        for (int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            visit[a[i]]=1;
        }
        int flag=0;
        for (int i=1;i<=205;i++){
            if (visit[i]==0){
                visit[i]=1;
                x--;
            }
            if (x==0)
                break;
        }
        for (int i=1;i<=205;i++)
        {if (visit[i]==1)
                flag=i;
        else
            break;}
            cout<<flag<<endl;
    }
    return 0;
}

B. Dreamoon Likes Permutations
啊啊这题一看就是一个模拟题某 我觉得群里另一个巨佬的思路应该更好 用前缀和
但在这里就拙劣的讲一下我的思路叭。我是先找左边的1位置计为l吧 右边的1计位r 然后i从l开始到r-1 开始找 如果某一个位置满足了第1到第i个位置满足了 是1-i的排列 那我就先记录下来 然后我在去判断每一个已经记录的位置 右边是不是也是1-(n-i)的排列 然后最后输出就好

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
    int t;
    cin>>t;
    while (t--){
        int a[200005];
        int n,l=0,r=0,visit1[200005]={0},visit2[200005]={0};
        int ccount1=0,ccount2=0,mx1=1,mx2=1;
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            if (a[i]==1)
            {
                if (l==0)
                    l=i;
                else
                    r=i;
            }
        }
        for (int i=l;i>=1;i--){
            if (visit1[a[i]]==0){
                visit1[a[i]]=1;
                ccount1++;
                mx1=max(mx1,a[i]);
            }
        }
        for (int i=r;i<=n;i++){
            if (visit2[a[i]]==0){
                visit2[a[i]]=1;
                ccount2++;
                mx2=max(mx2,a[i]);
            }
        }
        int ans1[200005]={0},ans=0,tot=0;
        for (int i=l;i<r;i++){
            if (visit1[a[i]]==0){
                visit1[a[i]]=1;
                ccount1++;
                mx1=max(mx1,a[i]);
            }
            if (mx1==ccount1&&mx1==i){
                ans1[++tot]=i;
            }
        }
        int now=r,m=tot;
        int check[200005]={0};
        for (;tot!=0;tot--){
            for (int i=now;i>ans1[tot];i--){
                if (visit2[a[i]]==0){
                    visit2[a[i]]=1;
                    ccount2++;
                    mx2=max(mx2,a[i]);
                }
            }
            if (mx2==ccount2&&mx2==n-ans1[tot]){
                {check[tot]=1;
                    ans++;
                }
            }
            now=ans1[tot];
        }
        cout<<ans<<endl;
        for (int i=1;i<=m;i++){
            if (check[i]==1){
                cout<<ans1[i]<<" "<<n-ans1[i]<<endl;
            }
        }
    }
    return 0;
}

C. Dreamoon Likes Coloring
这题先告诉大家可以用贪心来写
题意: 总共有n的小房间 然后你要涂m次颜色 第i次涂的长度已经告诉你 而且每次涂的长度不能浪费 比如这次要涂的长度是5 你就不能去涂倒数四个位置 然后最后保证全部的颜色都能出现 而且所有的房间都被涂过了
思路:我记录了所有涂的长度为sum 然后贪心的来讲吧 比如sum很大 比n大很多 那假如第一次涂的长度是10 那我们第二次在2这个位置涂的话 那是不是sum减去第一次的长度变成了sum-10 然后我们要涂的长度变成了n-1 那么sum就会向n靠近 (sum如果比n小那就肯定不行了) 然后每次涂的时候判断一下 比如我第一次涂10 那么我第二次是要在2 还是3 还是其他位置涂呢 最后n=sum的时候 就一直连着涂就好
ps 我的代码很长 我总想把一些已知的情况给去掉先 请大家多多包涵
如果要走我的思路的话 循环求a[i].ans的 可以自己好好推一下 理解一波

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
    int val,ans;
}a[100005];
int main() {
    int n,m,flag=0;
    ll sum=0;
    cin>>n>>m;
    for (int i=1;i<=m;i++)
    {scanf("%d",&a[i].val);
        if (i+a[i].val-1>n)
            flag=1;
        sum+=a[i].val;
    }
    if (flag){
        cout<<"-1"<<endl;
        return 0;
    }
    if (m>n||sum<n){
        cout<<"-1"<<endl;
        return 0;
    }
    int now=1;
    for (int i=1;i<=m;i++){
        if (sum!=n-now+1){
            a[i].ans=now;
            sum-=a[i].val;
            if (sum>=n-now){
                now++;
            }
            else{
                now=n-sum+1;
            }
        }
        else{
            a[i].ans=now;
            sum-=a[i].val;
            now+=a[i].val;
        }
    }
    if (now!=n+1)
        flag=1;
    if (flag){
        cout<<"-1"<<endl;
        return 0;
    }
    for (int i=1;i<=m;i++)
        cout<<a[i].ans<<" ";
    cout<<endl;
    return 0;
}

D. Dreamoon Likes Sequences
题意:每次会给你一个整数d和m m是取模的不用管他 计算的时候记得加上就好
那我们看看题意就是我们构造一个严格递增数组a 并且a[n]<=d 那我们可以理解成在1-d里面选数字组成 这个数组 同时我们还在构造一个数组b b1=a1,
b[i]=b[i-1]⊕a[i] 我们这里可以把 b[i]理解成 a1⊕a2⊕…⊕ai 同时这个数组也满足了严格递增的条件。问你a数组的种类数是多少 结果记得取模m
解法:那我们看到这里就知道这题肯定就是跟a数组怎么构造有关 a严格递增没什么好说的 我们就看b (异或 凡是看到这些就直接把数转成二进制然后去思考吧 cf题一般这样都能想出特点) 具体怎么想 我们最好还是看看样例 我们发现d=3的时候
1 2 ,1 3都满足条件 那么他们的数组b满足什么条件呢 我们发现b[i]的数的二进制的最高位一定会比b[i-1]的二进制最高位要高 这说明什么 说明a[i]的二进制最高位一定比a[i-1]的二进制的最高位要大 这也就解释了 为什么d=3的时候 2 3不行 (因为最高位是一样的啊 那我们就可以知道了a[i]的每一个数的最高位都是严格递增就行了 那么想到这里怎么写呢 这里我用到了以前fzh大佬给我讲题的一个思路 我们这么看 我们先假设d=7 那么4 5 6 7的最高位都是第三位 2 3是第二位 1是第一位 数组a的长度又不确定 那么这么想 1 也就是最高位是第一位的这个区间里面 我有两种选择 就是取1 或者不取 那么我们在看2 3这个区间 我有三种选择 不取 取2 取3 那么后面都是以此类推 所以d=7的时候结果是1* 2* 3*5-1。这里减1是因为 你要去掉你已经计算的 全部都不取的可能性 于是就解出来了
ps 记得判断 最后一个区间可能不是完全都能取的

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
    int t;
    cin>>t;
    while (t--){
        ll d,m;
        scanf("%lld%lld",&d,&m);
        ll ans=1,t=1;
        while (t<=d){
            ans=ans*(min(t,d-t+1)+1)%m;
            t<<=1;
        }
        cout<<(ans+m-1)%m<<endl;
    }
    return 0;
}

希望对大家有帮助嘻嘻