Educational Codeforces Round 170 (Rated for Div. 2)

A. Two Screens

题意

给你两个字符串 \(s,t\) ,和两个空的字符串,现在你有两种操作:

  • 在一个字符串末尾添加一个字母。
  • 将一个字符串替换为另一个字符串。

问你让两个空的字符串和 \(s,t\) 相同最少需要多少次操作。

思路

贪心。替换操作至多只会进行一次,且只能替换前缀相同的部分。维护一下最长公共前缀即可。

代码

void solve()
{
    string s,t;
    cin>>s>>t;
    int ans=s.size()+t.size(),num=0;
    for(int i=0;i<min(s.size(),t.size());i++)
    {
        if(s[i]!=t[i]) break;
        else num++;
    }
    
    if(num)cout<<ans-num+1<<endl;
    else cout<<ans<<endl;
}

B. Binomial Coefficients, Kind Of

题意

给你 \(t\)\(n,k\) ,对于每一个 \(n,k\) 都让你求一下这个递推式 \(C_{n,k}=C_{n-1,k}+C_{n-1,k-1}\)

思路

场上看样例猜的结论。答案其实就是 \(2^k\)
至于为什么我也来不及证明了,签到题秒了就行。

代码

int qpow(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
void solve()
{
    int n;
    cin>>n;
    vector<int> a(n+1),b(n+1);
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) cin>>b[i];
    for(int i=1;i<=n;i++) cout<<qpow(2,b[i])%mod<<endl;
}

C. New Game

题意

给你 \(n\) 个数 \(a_i\) ,你第一次可以任意的选择一个数,之后你选的数只能和上一次相等或者是上一次选的数 \(+1\) 。然后数字的种类不能超过 \(k\) 。问你最多选几个数。

思路

一开始我还想着离散化,结果发现排个序,用个队列就能过,类似于滑动窗口,然后统计一下这个队列里有多少种不同的数,每种数出现了多少次,然后答案对队列的大小取个 \(\text{MAX}\)
你说的对,但是这题我场上唐完了,写了一半没写完就交上了,害的我多了两罚罚时qwq。

代码

void solve()
{
    int n,k;
    cin>>n>>k;
    vector<int> a(n+1);
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a.begin()+1,a.end());
    queue<int> q;
    map<int,int> num;
    int ans=0,cnt=0;
    for(int i=1;i<=n;i++)
    {
        if(q.empty())
        {
            q.push(a[i]);
            num[a[i]]++;
            cnt++;
            ans=max(ans,(int)q.size());
        }
        else
        {
            if(q.back()==a[i])
            {
                q.push(a[i]);
                num[a[i]]++;
                ans=max(ans,(int)q.size());
            }
            else
            {
                if(a[i]==q.back()+1)
                {
                    q.push(a[i]);
                    num[a[i]]++;
                    cnt++;
                    while(q.size() && cnt>k)
                    {
                        int x=q.front();q.pop();
                        num[x]--;
                        if(!num[x]) cnt--;
                    }
                    ans=max(ans,(int)q.size());
                }
                else
                {
                    while(q.size())
                    {
                        int x=q.front();q.pop();
                        num[x]--;
                        if(num[x]==0) cnt--;
                    }
                    q.push(a[i]);
                }
            }
        }
    }
    cout<<ans<<endl;
}

D. Attribute Checks

题意

你现在有“知识”和“力量” 两项能力值,游戏过程中会有 \(m\) 个属性点,每次加属性可以选择增加“力量”或者“知识”。同时游戏中还会出现”能力考验“,当你对应的能力值大于等于游戏要求的能力值时获得 \(1\) 分。
现在给你一个序列 \(a_i\)

  • \(a_i=0\) 时,你可以选择一项能力值 \(+1\)
  • \(a_i>0\) 时,进行知识考验。
  • \(a_i<0\) 时,进行力量考验。

现在问你如何分配能力值才能获得的分数最大。

思路

这题真是一眼dp,设 \(dp_{i,j}\) 表示在第 \(i\)\(a_i=0\) 的位置知识能力值为 \(j\) 时能获得的最大分数。
转移的话就要考虑这个能力值给知识还是力量。然后他的贡献就是第 \(i\)\(a=0\) 的位置和第 \(i-1\)\(a=0\) 的位置之间有多少个能力考验的数值低于我 \(i-1\) 这个位置对应的能力值的。由于数据范围很小,我们可以开 \(m\) 个前缀和优化这个过程。最后时间复杂度 \(O(m^2)\) 。转移方程代码里写了,我这里就不写了。

代码

void solve()
{
    int n,m,cnt=0;
    cin>>n>>m;
    vector<int> a(n+1);
    vector<vector<int>> sum1(5002,vector<int>(5002));
    vector<vector<int>> sum2(5002,vector<int>(5002));
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        if(a[i]==0) cnt++;
        else if(a[i]>0)
            sum1[cnt][a[i]]++;
        else
            sum2[cnt][abs(a[i])]++;
    }
    if(a[n]!=0) m++;
    for(int j=1;j<=m;j++)
    {
        for(int i=1;i<=m;i++)
        {
            sum1[i][j]+=sum1[i][j-1];
            sum2[i][j]+=sum2[i][j-1];
        }
    }
    // for(int i=0;i<=m;i++)
    // {
    //     for(int j=0;j<=5;j++) cout<<sum1[i][j]<<' ';
    //     cout<<endl;
    // }
    vector<vector<int>> dp(m+2,vector<int>(m+2));
    int ans=0;
    for(int i=1;i<=m;i++)
    {
        for(int j=0;j<=i;j++)
        {
            int k=i-j;
            dp[i][j]=max(dp[i][j],dp[i-1][j]);
            if(j)
            {
                if(k) dp[i][j]=max(dp[i][j],dp[i-1][j-1]+sum1[i-1][j-1]+sum2[i-1][k]);
                else dp[i][j]=max(dp[i][j],dp[i-1][j-1]+sum1[i-1][j-1]);
            }
            if(k)
            {
                if(j) dp[i][j]=max(dp[i][j],dp[i-1][j]+sum2[i-1][k-1]+sum1[i-1][j]);
                else dp[i][j]=max(dp[i][j],dp[i-1][j]+sum2[i-1][k-1]);
            }
            ans=max(ans,dp[i][j]);
        }
    }
    cout<<ans<<endl;
}
posted @ 2024-10-15 00:54  杨丶老爹  阅读(391)  评论(3编辑  收藏  举报