A

知识点:贪心、乘法原理
思路:如果是给定的字符串,那么dp求解即可。但这道题只给了1、2、4的数量。显然111...1144...44111...11222...22这样是最优的,且两个1的连续子串长度之差尽可能小。
最终输出 即可。

#include<bits/stdc++.h>;
using namespace std;
#define ll long long
const int mod = 1e9+7;

int main(){
    ll t;
    cin>>t;
    while(t--){
        ll n,m,k;
        cin>>n>>m>>k;
        ll a=n/2,b=n-a;
        cout<<a*b*m*k<<endl;
    }
}

B

知识点:图论
思路:统计所有点的度数,那么每个点距离为 的数量为它的邻点的度数之和减去邻点的个数。

#include<bits/stdc++.h>;
using namespace std;
#define ll long long
const int mod = 1e9+7;
int dp[222222];
vector<int>g[222222];
int main(){
    ll n,i,j,k;
    cin>>n;
    for(i=1;i<n;i++){
        ll x,y;
        cin>>x>>y;
        g[x].push_back(y);
        g[y].push_back(x);
        dp[x]++;
        dp[y]++;
    }
    for(i=1;i<=n;i++){
        ll sum=0;
        for(j=0;j<g[i].size();j++){
            sum+=dp[g[i][j]]-1;
        }
        cout<<sum<<endl;
    }
}

C

知识点:dp
思路:这道题其实就是求所有子区间的区间内部两两乘积之和。
我们先把问题分解,假设 为前 个数的最终答案,那么 多了哪些区间呢?答案是这些。
那么我们可以先转换一下思路,设 这些区间内部的两两乘积之和,这些区间里的乘积可以分为两类,含 的和不含 的。
的部分,有 , , ... 。这些部分可以前缀和预处理搞定。
不含 的部分,可以看成为 这些区间内部的两两乘积之和,正好是dp2[i-1]。
那么这道题就做出来了。
(当时推的时候思路没这么清晰,把 单独拿出来了,繁琐了很多)。

#include<bits/stdc++.h>;
using namespace std;
#define ll long long
const int mod = 1e9+7;
ll dp[200202],dp2[200020],sum[200020],dpp[200020];
ll a[200202];
ll power(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1)res=res*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return res;
}
int main(){
    ll n,i,j,k;
    cin>>n;
    for(i=1;i<=n;i++){
        cin>>a[i];
        sum[i]=sum[i-1]+a[i];
        dp2[i]=dp2[i-1]+sum[i];
        sum[i]%=mod;
        dp2[i]%=mod;
    }
    dpp[1]=a[1]*a[1];
    for(i=2;i<=n;i++){
        dpp[i]=dpp[i-1]+(sum[i-1]*i%mod-dp2[i-1]+mod)*a[i]%mod+(i)*a[i]%mod*a[i]%mod;
        dpp[i]%=mod;
    }
    //for(i=1;i<=n;i++)cout<<sum[i]<<" "<<dpp[i]<<endl;
    for(i=1;i<=n;i++)
    dp[1]=a[1]*a[1];
    for(i=2;i<=n;i++){
       // cout<<(sum[i-1]*i%mod-dp2[i-1]+mod)%mod<<endl;
        dp[i]=dp[i-1]+a[i]*a[i]%mod*i%mod+(sum[i-1]*i%mod-dp2[i-1]+mod)*a[i]%mod+dpp[i-1];
        dp[i]%=mod;
    }
    cout<<dp[n];
}

D

知识点:dp、容斥原理
思路:这道题直接正向求不太好求,可以反向思维:一共有 个排列,把所有不合法的情况减去,就是合法的情况。
不合法的情况可以这样去求:
先用一个桶来统计每个位置的不合法的宝石数量( 可以跳过不统计),记为
首先有1个位置不合法的总方案共有
2个位置不合法的总方案共有
3个位置不合法的总方案共有
问题就是如何求里面的和式了。这个可以用二维dp解决,设 为前 个数里,取 个数乘积之和,那么有:
求完了这些之后,我们可以用 减去1个位置不合法的方案数,那么2个位置不合法的情况被多减了一次,需要加回来,3个位置不合法的情况又被加多了,再减掉。。以此类推,最终求出来的就是合法方案的总数。
注意这道题 范围是8000, 的时间复杂度可以过,但空间复杂度不行,所以只能开滚动数组进行dp(我就是第一发开的二维数组导致mle一次QAQ)

#include<bits/stdc++.h>;
using namespace std;
#define ll long long
const int mod = 998244353;
ll jc[200020];
ll power(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1)res=res*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return res;
}
ll inv(ll x){
    power(x,mod-2);
}
ll a[20002],t[20002],b[20002],dp[3][8002];
int main(){
    ll n,i,j=1,k;
    cin>>n;
    ll tt=1;
    jc[0]=1;
    for(i=1;i<=n;i++)jc[i]=tt=tt*i%mod;
    for(i=0;i<n;i++)cin>>a[i],t[a[i]]++;
    int jud=-1,temp=n;
    for(i=1;i<=n;i++){
        if(t[i])b[j++]=t[i];
    }
    j--;

    //for(i=1;i<=j;i++)cout<<dp[i][j]<<endl;
    ll res=jc[n];
    for(i=1;i<=j;i++){
        if(i==1){
            for(k=1;k<=j;k++){
                dp[1][k]=(dp[1][k-1]+b[k])%mod;
            }
        }
        else{
            for(k=1;k<=j;k++){
                dp[0][k]=dp[1][k];
            }
            for(k=1;k<=j;k++){
                dp[1][k]=(dp[1][k-1]+dp[0][k-1]*b[k])%mod;
            }
        }
        res+=jud*jc[n-i]*dp[1][j]%mod,jud*=-1;
        res=(res+mod)%mod;
     //   cout<<res<<endl;
    }
    cout<<res;
}