每一年都奔走在自己热爱里

没有人是一座孤岛,总有谁爱着你

Educational Codeforces Round 144 (Rated for Div. 2)(A,B,C,D)

Educational Codeforces Round 144 (Rated for Div. 2)(A,B,C,D)

本来这场我是要\(vp\)的,但是后来第一个题\(wa\)了一次,心态崩了,就没有看了,后面才补的

A

A

这个就是求一个串是不是另外一个串的子串,我都知道了这个另外一个串是什么了,就是我是自己写的判断两个字符串是否是为子串的关系写错了(还是太弱了),其实我们可以看到\(k\)的大小是不大的,所以我们可以根据我所得到的的规律构造一个串(长度比\(k\)大),然后利用\(find\)来判断

我觉得我在做这个题的时候没有看到那个\(k\)的范围,然后就一股脑的去写,ε=(´ο`*)))

#include <iostream>
#include <string>
using namespace std;
const int manx=2e5+10;
int t,n;
string ss="FBFFBFFB";
void solve()
{
    string s;
    cin>>n;
    cin>>s;
    if (ss.find(s)!=-1)
    {
        cout<<"YES\n";
    }
    else cout<<"NO\n";
    return ;
}
int main ()
{
    cin>>t;
    ss=ss+ss+ss;
    while (t--)
    {
        solve();
    }
    system ("pause");
    return 0;
}

B

B

这个是我后面自己写的

题目大意就是我们可以用一个既有\(*\)又有字母的字符串,我们可以把\(*\)变成任意的字符(长度不定),然后给出我们两个字符串,找到一个上面所述的形式的字符,这个字符串可以得到这两种字符,但是还要满足字母的数量不可以大于\(*\)的数量

我们可以知道,如果对于两个字符串都存在的字符,那么那么这一个字符就可以直接显示出来,而不需要通过\(*\)变成,所以对于那些两个字符串都存在的字符,我们就是以字母的形式

然后我们对于那些不同的,我们直接用\(*\)变成

然后我们还知道\(*a*a*\)这样的字符串,\(*\)一定是大于字母的数量的

所以我们只有两端的字符是一样的,那么我们后面都由 \(*\)变成,符号条件

那么对于那些两端不同的,只有中间存在两个连续的字符在两个字符串里面是一样的,那么就会变成\(*ab*\),符号条件,如果不满足,那么就只有\(*a*\),不满足条件

#include <iostream>
#include <string>
using namespace std;
const int maxn=2e5+10;
#define yes cout<<"YES\n"
#define no cout<<"NO\n";
int t;
string s,ss;
void solve()
{
    cin>>s>>ss;
    if (s[0]==ss[0])
    {
        yes;
        cout<<s[0]<<"*\n";
        return ;
    }
    int n=s.size(),nn=ss.size();
    if (s[n-1]==ss[nn-1])
    {
        yes;
        cout<<"*"<<s[n-1]<<'\n';
        return ;
    }
    for (int i=0;i+1<n;i++)
    {
        for (int j=0;j+1<nn;j++)
        {
            if (s[i]==ss[j]&&s[i+1]==ss[j+1])
            {
                yes;
                cout<<"*"<<s[i]<<s[i+1]<<"*\n";
                return ;
            }
        }
    }
    no;
    return ;
}
int main ()
{
    cin>>t;
    while (t--)
    {
        solve();
    }
    system ("pause");
    return 0;
}

C

C

题目大意就是给你一对\(l\)\(r\),我们需要在这一段里面找任意个数,使得我所选择的数是两两可整除的,问我所选择的数的数量最大是多少,这个数量的数有多少种选择

首先我们需要知道这个最大的数量是多大

要满足数量最多,那么这个最小的数一定是\(l\),要满足两两可整除,那么后面的我们可以依次乘\(2\),那么最大数量\(len\),第\(len\)大的数是$ l\times 2^{len-1}\(,这个数是最后一个小于\)r\(的,那么我们可以得到\)len=log2(r/l)$,对于所有的都是\(2\),然后我们还可以把这个\(2\)替换成\(3\),但是不可以是\(4\),一定是不满足的

对于最大的数是最小的数的\(2^{len-1}\)(\(mul\))倍,只要这个最大的在\(r\)的范围内的均可,所以对于这一种倍数满足条件的有多少个,我们可以求出最后一个满足这个条件( \(r/mul\))的,那么这个数到\(l\)的范围都是满足条件的

但是注意对于把任意个\(2\)变成\(3\),有不同的组合方式

#include <iostream>
#include <cmath>
using namespace std;
#define int long long 
const int mod=998244353;
int n,t,l,r;
int c[40][40];
void init()
{
    for (int i=0;i<=30;i++)
    {
        for (int j=0;j<=i;j++)
        {
            if (!j)
            {
                c[i][j]=1;
            }
            else 
            {
                c[i][j]=c[i-1][j-1]+c[i-1][j];
            }
        }
    }
    return ;
}
void solve()
{
    cin>>l>>r;
    int len=__lg(r/l);
    int mul=1<<len;
    int ans=0;
    for (int i=0;i<=len;i++)
    {
        if (l*mul>r) break;
        ans=(ans+c[len][i]*(r/mul-l+1)%mod)%mod;
        mul=mul*3/2;
    }
    cout<<len+1<<" "<<ans<<'\n';
    return ;
}
signed main ()
{
    cin>>t;
    init();
    while (t--)
    {
        solve();
    }
    system ("pause");
    return 0;
}

D

D

这个大意是给你一个\(n\)个数,我们需要选择\(k\)个数,把这\(k\)个数加\(x\),其余的减\(x\),问最大子段和

这个我们可以参考普通的最大字段和

for (int i=1;i<=n;i++)
{
    dp[i]=max(dp[i-1]+a[i],a[i]);//以i为结尾的最大子段和
}

最大子段和

然后我们这个题还需要选择\(k\)个加\(x\),其余减\(x\)的变化

所以我们还需要多一维来表达这个位置是加还是减,还需要记录此时已经有了多少个加了

那么对于\(dp[i] [j] [x] [y]\)代表此时已经遍历的\(i\)的长度,已经有了\(j\)个加法操作了,\(x\)\(0\),\(1\)表示,代表\(i\)位置的数是加法还是减法,\(y\)\(0\),\(1\)表示,代表\(i\)位置的数放进子段里面还是不放

然后我们就可以很容易的得出状态转移方程

 if (i>j)//最多只能有i-1个,他前面只有i-1个位置(不包括i),第i个进行减法操作
 {
     dp[i][j][0][0]=max(dp[i-1][j][0][0],max(dp[i-1][j][0][1],max(dp[i-1][j][1][0],max(dp[i-1][j][1][1],0ll))));
     dp[i][j][0][1]=max(dp[i-1][j][0][1]+t0,max(dp[i-1][j][1][1]+t0,t0));
 }
if (j)//加法操作,这一项的j可以等于i,可以前面到i都是加法
{
    dp[i][j][1][0]=max(dp[i-1][j-1][0][0],max(dp[i-1][j-1][0][1],max(dp[i-1][j-1][1][0],max(dp[i-1][j-1][1][1],0ll))));
    dp[i][j][1][1]=max(dp[i-1][j-1][0][1]+t1,max(dp[i-1][j-1][1][1]+t1,t1));
}

具体代码如下

#include <iostream>
using namespace std;
const int maxn=2e5+10;
#define int long long 
int dp[maxn][30][2][2];
int a[maxn];
int n,k,x;
void solve()
{
    cin>>n>>k>>x;
    for (int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    for (int i=0;i<2;i++)
    {
        for (int j=0;j<2;j++)
        {
            dp[0][0][i][j]=0;
        }
    }
    for (int i=1;i<=n;i++)
    {
        for (int j=0;j<=min(i,k);j++)
        {
            int t1=a[i]+x;
            int t0=a[i]-x;
            if (i>j)//最多只能有i-1个,他前面只有i-1个位置(不包括i),第i个进行减法操作
            {
                dp[i][j][0][0]=max(dp[i-1][j][0][0],max(dp[i-1][j][0][1],max(dp[i-1][j][1][0],max(dp[i-1][j][1][1],0ll))));
                dp[i][j][0][1]=max(dp[i-1][j][0][1]+t0,max(dp[i-1][j][1][1]+t0,t0));
            }
            if (j)//加法操作,这一项的j可以等于i,可以前面到i都是加法
            {
                dp[i][j][1][0]=max(dp[i-1][j-1][0][0],max(dp[i-1][j-1][0][1],max(dp[i-1][j-1][1][0],max(dp[i-1][j-1][1][1],0ll))));
                dp[i][j][1][1]=max(dp[i-1][j-1][0][1]+t1,max(dp[i-1][j-1][1][1]+t1,t1));
            }
        }
    }
    int ans=0;
    for (int i=0;i<2;i++)
    {
        for (int j=0;j<2;j++)
        {
            ans=max(ans,dp[n][k][i][j]);
        }
    }
    cout<<ans<<'\n';
    return ;
}
signed main ()
{
    int t;
    cin>>t;
    while (t--)
    {
        solve();
    }
    system ("pause");
    return 0;
}
posted @ 2023-03-05 00:09  righting  阅读(83)  评论(0)    收藏  举报