CR604 题解
vp 场上做出 ABC,排名一百多,还是有点拉垮。
A. Beautiful Regional Contest
考虑贪心,金牌就选一种,银牌尽可能地少选,铜牌在满足条件下尽可能多选。
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=5e5+10;
const int mod=1e9+7;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m,T,a[maxn],st[maxn],top,cnt[maxn];
int main(){
T=read();
while(T--){
n=read();top=0;
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=n;i++)
if(!top||a[i]!=st[top])st[++top]=a[i],cnt[top]=1;
else cnt[top]++;cnt[++top]=inf,cnt[++top]=inf;
int g=cnt[1],s=0,c=2,b=0;
for(;c<=top&&s<=g;c++)s+=cnt[c];//c++;
for(;c<=top&&b<=g;c++)b+=cnt[c];
for(;c<=top&&s+b+g+cnt[c]<=n/2;c++)b+=cnt[c];
if(s+g+b>n/2)puts("0 0 0");
else printf("%d %d %d\n",g,s,b);
}
return 0;
}
B. Beautiful Sequence
最终的序列一定长成一段 01,一段 12,一段 23 的样子,分类讨论即可。
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m,a,b,c,d,p[maxn];
int main(){
a=read(),b=read(),c=read(),d=read();
if(a>b+1)return puts("NO")&0;
if(a==b+1){
if(c||d)return puts("NO")&0;
puts("YES");
for(int i=1;i<=a;i++){
putchar('0'),putchar(' ');
if(i<a)putchar('1'),putchar(' ');
}return 0;
}
if(d>c+1)return puts("NO")&0;
if(d==c+1){
if(a||b)return puts("NO")&0;
puts("YES");
for(int i=1;i<=d;i++){
putchar('3'),putchar(' ');
if(i<d)putchar('2'),putchar(' ');
}return 0;
}
int len=a+b+c+d;
int bb=b-a,cc=c-d;
if(abs(bb-cc)>1)return puts("NO")&0;
if(bb>cc){
for(int i=1;b;i+=2)p[i]=1,b--;
for(int i=2;a;i+=2)p[i]=0,a--;
for(int i=len;d;i-=2)p[i]=3,d--;
for(int i=len-1;c;i-=2)p[i]=2,c--;
}else if(cc>bb){
for(int i=2;b;i+=2)p[i]=1,b--;
for(int i=1;a;i+=2)p[i]=0,a--;
for(int i=len-1;d;i-=2)p[i]=3,d--;
for(int i=len;c;i-=2)p[i]=2,c--;
}else{
for(int i=2;b;i+=2)p[i]=1,b--;
for(int i=1;a;i+=2)p[i]=0,a--;
for(int i=len;d;i-=2)p[i]=3,d--;
for(int i=len-1;c;i-=2)p[i]=2,c--;
}puts("YES");
for(int i=1;i<=len;i++)
printf("%d ",p[i]);puts("");
return 0;
}
C. Beautiful Mirrors with queries
C 题不难,一下就会了,可是因为一些神秘错误 debug 太久。
考虑平方的做法,设 \(f_i\) 为从 \(i\) 开始的答案,\(las\) 为上一个存档点,则有 \(f_i=p_if_{i+1}+(1-p_i)f_{las}+1\)
考虑对于一个存档点 \(las\),设其下一个为 \(nex\),则有 \(f_{las}=\sum\limits_{i=las}^{nex-1} (i-las+1+f_{las})(1-p_i)\prod\limits_{j=las}^{i-1} p_j+(f_{nex}+nex-las)\prod\limits_{i=las}^{nex-1} p_i\)
化简后发现 \(f_{las}=f_{nex}+nex-las+F(las,nex)\),维护即可。
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=998244353;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
inline int ksm(int x,int y){
int res=1;
while(y){
if(y&1)res=1ll*res*x%mod;
x=1ll*x*x%mod;y>>=1;
}return res;
}
const int iv100=ksm(100,mod-2);
int n,q,p[maxn],val[maxn];
set<int>S;
set<int>::iterator it,it1;
int sp[maxn],ssp[maxn],isp[maxn],ans;
inline int calc(int l,int r){return 1ll*sp[r]*isp[l-1]%mod;}
inline void modify(int now){
ans=(ans-val[now]+mod)%mod;
it1=S.upper_bound(now);int nex=*it1;
//printf("modify now=%d nex=%d\n",now,nex);
int res=1ll*(ssp[nex-2]-ssp[now-1]+mod)*isp[now-1]%mod;
res=(res-1ll*(nex-now)*calc(now,nex-1))%mod;
//printf("now res=%d\n",res);
res=(res+mod+1)%mod;res=1ll*res*ksm(calc(now,nex-1),mod-2)%mod;
val[now]=res;ans=(ans+res)%mod;
}
int main(){
n=read(),q=read();ans=n;
for(int i=1;i<=n;i++)
p[i]=1ll*read()*iv100%mod;
sp[0]=isp[0]=1;
for(int i=1;i<=n;i++)
sp[i]=1ll*sp[i-1]*p[i]%mod;
for(int i=1;i<=n;i++)
isp[i]=1ll*isp[i-1]*ksm(p[i],mod-2)%mod;
for(int i=1;i<=n;i++)
ssp[i]=(ssp[i-1]+sp[i])%mod;
S.insert(1);S.insert(n+1);modify(1);
//printf("ans=%d\n",ans);
for(int i=1,x;i<=q;i++){
x=read();it=S.lower_bound(x);
if(*it==x){
it--;S.erase(x);
ans=(ans-val[x]+mod)%mod;val[x]=0;
modify(*it);
}else{
it--;S.insert(x);
modify(*it);modify(x);
}printf("%d\n",ans);
}
return 0;
}
D. Beautiful Bracket Sequence
考虑对一个给定的括号序列,怎么求其深度。枚举分割点,左边左括号和右边右括号的较小值的最大值。
注意到一个事情,对于一个最深的括号匹配,存在且仅存在一个分割点使得左边的左括号和右边的右括号个数相等,证明显然。
那么我们枚举分割点,枚举深度,就做完了 Easy Version。
然后你看看这个式子,\(\sum\limits_{j=0}^u (l+j)\binom{u}{j}\binom{v}{l+j-r}\),就差把范德蒙德四个字写脸上了。
//D1
#include<bits/stdc++.h>
using namespace std;
const int N=2e3+5;
const int mod=998244353;
string s;
int n,fac[N],ifc[N],inv[N];
int pl[N],pr[N],pw[N],ans;
inline int com(int x,int y){
if(x<y||x<0||y<0)return 0;
return 1ll*fac[x]*ifc[y]%mod*ifc[x-y]%mod;
}
int main(){
cin>>s;n=s.size();
s=" "+s;
inv[1]=fac[0]=ifc[0]=1;
for(int i=2;i<=n;i++)
inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(int i=1;i<=n;i++)
fac[i]=1ll*fac[i-1]*i%mod;
for(int i=1;i<=n;i++)
ifc[i]=1ll*ifc[i-1]*inv[i]%mod;
for(int i=1;i<=n;i++){
pl[i]=pl[i-1]+(s[i]=='(');
pw[i]=pw[i-1]+(s[i]=='?');
}
for(int i=n;i;--i)
pr[i]=pr[i+1]+(s[i]==')');
for(int i=1;i<n;i++){
int l=pl[i],u=pw[i];
int r=pr[i+1],v=pw[n]-pw[i];
for(int j=0;j<=u;j++)
ans=(ans+1ll*(l+j)*com(u,j)%mod*com(v,l+j-r))%mod;
}printf("%d\n",ans);
return 0;
}
//D2
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+5;
const int mod=998244353;
string s;
int n,fac[N],ifc[N],inv[N];
int pl[N],pr[N],pw[N],ans;
inline int com(int x,int y){
if(x<y||x<0||y<0)return 0;
return 1ll*fac[x]*ifc[y]%mod*ifc[x-y]%mod;
}
int main(){
cin>>s;n=s.size();
s=" "+s;
inv[1]=fac[0]=ifc[0]=1;
for(int i=2;i<=n;i++)
inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(int i=1;i<=n;i++)
fac[i]=1ll*fac[i-1]*i%mod;
for(int i=1;i<=n;i++)
ifc[i]=1ll*ifc[i-1]*inv[i]%mod;
for(int i=1;i<=n;i++){
pl[i]=pl[i-1]+(s[i]=='(');
pw[i]=pw[i-1]+(s[i]=='?');
}
for(int i=n;i;--i)
pr[i]=pr[i+1]+(s[i]==')');
for(int i=1;i<n;i++){
int l=pl[i],u=pw[i];
int r=pr[i+1],v=pw[n]-pw[i];
ans=(ans+1ll*l*com(u+v,r-l+v))%mod;
ans=(ans+1ll*u*com(u+v-1,r-l+v-1))%mod;
}printf("%d\n",ans);
return 0;
}
E. Beautiful League
哎,题目名这么眼熟?哦,石头剪刀布重题是吧,那没事了。
F. Beautiful Fibonacci Problem
人力不可及好吧。以后再说吧。