Educational Codeforces Round 185 (Rated for Div. 2) 记录
Educational Codeforces Round 185 (Rated for Div. 2) 记录
糖丸的一场,早早三个题但是没把D的啥比错误看出来,赛后B因为不开long long 见祖宗了。
A
可以贪心地取右下的几个可能作为答案的点,但是由于数据范围较小,暴力求解也可以通过。
B
由于需要求的是
而假设第一步操作对一个长度为
将数组
C
注意到题目中其实给出了一个标准的带余除法的形式,稍加转化即可变为:
其中
注意到左边式子的值随
#include<bits/stdc++.h>
using namespace std;
#define int long long
int T;
const int N=2e5+10;
int n,k;
int q[N],rr[N];
void solve(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>q[i];
}
for(int i=1;i<=n;i++){
cin>>rr[i];
}
sort(q+1,q+n+1);
sort(rr+1,rr+n+1);
int l,r;
l=1,r=n;
int ans=0;
while(l<=n && r>=1){
if(q[l]*(rr[r]+1)+rr[r]<=k){
l++;
r--;
ans++;
}else{
r--;
}
}
cout<<ans<<'\n';
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>T;
for(int i=1;i<=T;i++){
solve();
}
return 0;
}
D
注意到当有
接下来再考虑怎么填比较优。这里我们可以把这个串中各个连续的问号段拉出来一个个单独考虑,因为
其中的
对于第一类点,假设将其值变为
同理第二类为
因此转换顺序为一类点-二类点-三类点。
此时则会出现一个问题,在转化过程中点的类型可能会发生变化。这个只需先将一类点标记完再考虑二类点,剩下的均化为三类点即可。
而对于各个连续问号段,我们还需要讨论它两边字符的值才能计算其中各类点的数量。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=3e5+10;
int T;
int n,q;
char s[N];
void solve(){
cin>>n>>q;
for(int i=1;i<=n;i++) cin>>s[i];
int s1=0;
int s2=0;
int s3=0;
int res=0;
int ss=0;
for(int i=1;i<=n;i++){
if(s[i]=='X') res+=10;
else if(s[i]=='V') res+=5;
else{
if(i+1<=n && (s[i+1]=='X' || s[i+1]=='V')) res--;
else res++;
}
if(s[i]=='?') ss++;
}
s[n+1]='I';
s[0]='X';
int ss1,ss2,ss3;
for(int i=1;i<=n;i++){
if(s[i]=='?'){
int j=i;
while(s[j]=='?') j++;
j--;
int len=j-i+1;
ss1=ss2=ss3=0;
// cout<<i<<" "<<j<<'\n';
if(s[i-1]=='I' && s[j+1]=='I'){
ss1+=len/2+((len&1)?1:0);
ss2+=(len&1)?0:1;
ss3+=len-ss1-ss2;
}else if(s[i-1]=='I'){
ss1+=len/2;
ss2+=(len&1);
ss3=len-ss1-ss2;
}else if(s[j+1]=='I'){
ss1+=len/2;
ss2+=(len&1);
ss3+=len-ss1-ss2;
}else{
if(len&1){
ss1=len/2;
ss3=len-ss1;
}else{
ss1=len/2-1;
ss2=1;
ss3=len-ss1-ss2;
}
}
// cout<<ss1<<" "<<ss2<<" "<<ss3<<'\n';
s1+=ss1;
s2+=ss2;
s3+=ss3;
// cout<<s1<<" "<<s2<<" "<<s3<<'\n';
i=j;
}
}
// cout<<s1<<" "<<s2<<" "<<s3<<'\n';
// cout<<res<<'\n';
ss1=s1,ss2=s2,ss3=s3;
while(q--){
int cx,cy,cz;
cin>>cx>>cy>>cz;
int ans=res;
if(cz>=ss){
cout<<ans<<'\n';
continue;
}
s1=ss1,s2=ss2,s3=ss3;
int now=ss-cz;
if(cy<=now){
now-=cy;
if(cy>=s1){
cy-=s1;
ans+=s1*2;
s1=0;
}else{
ans+=cy*2;
s1-=cy;
cy=0;
}
if(cy>=s2){
cy-=s2;
ans+=s2*4;
s2=0;
}else{
ans+=cy*4;
s2-=cy;
cy=0;
}
if(cy>=s3){
cy-=s3;
ans+=s3*6;
s3=0;
}else{
ans+=cy*6;
s3-=cy;
cy=0;
}
// cout<<"ok "<<ans<<'\n';
if(now>=s1){
now-=s1;
ans+=s1*7;
s1=0;
}else{
ans+=now*7;
now-=s1;
now=0;
}
if(now>=s2){
now-=s2;
ans+=s2*9;
s2=0;
}else{
ans+=now*9;
s2-=now;
now=0;
}
if(now>=s3){
now-=s3;
ans+=s3*11;
s3=0;
}else{
ans+=now*11;
s3-=now;
now=0;
}
cout<<ans<<'\n';
}else{
if(now>=s1){
now-=s1;
ans+=s1*2;
s1=0;
}else{
ans+=now*2;
s1-=now;
now=0;
}
if(now>=s2){
now-=s2;
ans+=s2*4;
s2=0;
}else{
ans+=now*4;
s2-=now;
now=0;
}
if(now>=s3){
now-=s3;
ans+=s3*6;
s3=0;
}else{
ans+=now*6;
s3-=now;
now=0;
}
cout<<ans<<'\n';
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>T;
for(int i=1;i<=T;i++){
solve();
}
return 0;
}
E
稍加观察容易发现,当block数量为1是不行的,而当其数量大于一时,若有偶数个block,移除开头的即可转化为奇数个,若有奇数个block,移除中间的一个即可。所以字符串是完美的等价于这个字符串中的字符不全相等。
考虑dp。 记
这个式子的实际意义即为:对于每个
在这之后我们再考虑题目中给出的各个区间的限制。对于一个区间
此时我们记以
最后dp转移的时候前缀和优化即可。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
const int N=3e5+10;
int T;
int n,m;
int f[N],sum[N];
int R[N];
void solve(){
cin>>n>>m;
for(int i=1;i<=m;i++){
int l,r;
cin>>l>>r;
R[r]=max(R[r],l);
}
for(int i=1;i<=n;i++) R[i]=max(R[i],R[i-1]);
sum[0]=f[0]=1;
for(int i=1;i<=n;i++){
if(R[i]){
f[i]=(sum[i-1]-sum[R[i]-1]+mod)%mod;
f[i]%=mod;
}else{
f[i]=sum[i-1];
f[i]%=mod;
}
sum[i]=sum[i-1]+f[i];
sum[i]%=mod;
// cout<<f[i]<<" ";
}
// cout<<'\n';
cout<<2*f[n]%mod<<'\n';
for(int i=1;i<=n;i++) R[i]=0;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>T;
for(int i=1;i<=T;i++){
solve();
}
return 0;
}