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
这个就是求一个串是不是另外一个串的子串,我都知道了这个另外一个串是什么了,就是我是自己写的判断两个字符串是否是为子串的关系写错了(还是太弱了),其实我们可以看到\(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
这个是我后面自己写的
题目大意就是我们可以用一个既有\(*\)又有字母的字符串,我们可以把\(*\)变成任意的字符(长度不定),然后给出我们两个字符串,找到一个上面所述的形式的字符,这个字符串可以得到这两种字符,但是还要满足字母的数量不可以大于\(*\)的数量
我们可以知道,如果对于两个字符串都存在的字符,那么那么这一个字符就可以直接显示出来,而不需要通过\(*\)变成,所以对于那些两个字符串都存在的字符,我们就是以字母的形式
然后我们对于那些不同的,我们直接用\(*\)变成
然后我们还知道\(*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
题目大意就是给你一对\(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
这个大意是给你一个\(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;
}

浙公网安备 33010602011771号