【日常摸鱼】ARC113
前言
无
A A*B*C
水题略了
B A^B^C
一个sb题我居然卡了好久。。求(A^{B^C}mod10)直接套扩展欧拉定理就行了
C String Invasion
水题略了
D Sky Reflector
链接
https://atcoder.jp/contests/arc113/tasks/arc113_d
题意
n行m列的矩阵,每个格子随意填1到k的任意数字,A[i]表示第i行的最小值,B[i]表示第i列的最大值。
问有多少种不同的{A,B}
(n,m,kleq 200000)
题解
n=1和m=1可以直接特判掉。
行列都大于1的时候,只需满足max{A[i]}<=min{B[i]}就是合理的方案,然后就是计算了。
(Code)
#include <bits/stdc++.h>
#define LL long long
#define LD long double
using namespace std;
const LL P=998244353;
const int N=3e5+10;
const int INF=1e9;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void print(LL x){
if(x>9) print(x/10);
putchar(x%10+'0');
}
void pls(LL &x,LL y){
x+=y;if(x>=P)x-=P;
}
LL qpow(LL x,LL y){
LL re=1;
while(y){
if(y&1)re=re*x%P;
x=x*x%P;y>>=1;
}
return re;
}
LL n,m,K;
LL F[200005];
void MAIN(){
cin>>n>>m>>K;
if(n==1&&m==1){
cout<<K%P<<endl;
return;
}
if(m==1) swap(n,m);
if(n==1){
cout<<qpow(K,m)<<endl;
return;
}
if(n>1&&m>1){
for(LL i=1;i<=K;++i){
F[i]=qpow(i,n);
}
for(LL i=K;i>1;--i){
F[i]=(F[i]-F[i-1]+P)%P;
}
//for(int i=1;i<=K;++i) cout<<F[i]<<" ";cout<<endl;
LL ans=0;
for(LL i=1;i<=K;++i){
ans+=F[i]*qpow(K-i+1,m)%P;
}
ans=(ans%P+P)%P;
cout<<ans<<endl;
return;
}
}
int main(){
int ttt=1;
while(ttt--) MAIN();
return 0;
}
E Rvom and Rsrev
链接
https://atcoder.jp/contests/arc113/tasks/arc113_e
题意
给一个只有a和b的字符串S,每次可以选择两个位置i,j(i<j并且S[i]=S[j]),令字符串的i到j之间的串翻转。可以操作任意次,问能得到的字典序最大的串。多组数据。
(sum|S|leq 200000)
题解
就是个大讨论,具体看代码吧。
(Code)
#include <bits/stdc++.h>
#define LL long long
#define LD long double
using namespace std;
const LL P=998244353;
const int N=3e5+10;
const int INF=1e9;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void print(LL x){
if(x>9) print(x/10);
putchar(x%10+'0');
}
void pls(LL &x,LL y){
x+=y;if(x>=P)x-=P;
}
LL qpow(LL x,LL y){
LL re=1;
while(y){
if(y&1)re=re*x%P;
x=x*x%P;y>>=1;
}
return re;
}
char s[200005];
int q[200005];
int tp;
void MAIN(){
scanf("%s",s+1);
int n=strlen(s+1);
bool flag=0;
for(int i=1;i<=n;++i) if(s[i]=='a') flag=1;
if(!flag){
printf("%s
",s+1);
return;
}
flag=0;
for(int i=1;i<=n;++i) if(s[i]=='b') flag=1;
if(!flag){
printf("%s
",s+1);
return;
}
if(s[n]=='a'){
tp=0;int x=0,y=0;
for(int i=1;i<=n;++i){
if(s[i]=='a') ++x;
else {
if(x>0){
q[++tp]=x;
x=0;
}
++y;
}
}
if(x>0) q[++tp]=x;
x=0;
for(int i=1;i<tp;++i){
if(q[i]>1) q[tp]=q[tp]+q[i]-2;
else ++x;
}
x=x%2;
if(x)q[tp]=q[tp]+x-2;
for(int i=1;i<=y;++i) putchar('b');
for(int i=1;i<=q[tp];++i) putchar('a');
puts("");
return;
}
else{
int x=0,y=0;
for(int i=n;i>=1;--i){
if(s[i]=='a') ++x;
else ++y;
}
if(x%2==0){
for(int i=1;i<=y;++i) putchar('b');puts("");
}
else if(s[n-1]=='a'){
for(int i=1;i<y;++i) putchar('b');
putchar('a');putchar('b');
puts("");
}
else if(s[n-2]=='a'){
for(int i=1;i<y-1;++i) putchar('b');
putchar('a');putchar('b');putchar('b');
puts("");
}
else {
tp=0;x=0;y=0;
for(int i=1;i<=n;++i){
if(s[i]=='a') ++x;
else {
if(x>0){
q[++tp]=x;
x=0;
}
++y;
}
}
if(x>0) q[++tp]=x;
if(tp==1&&s[1]=='a'){
putchar('a');
for(int i=1;i<=y;++i) putchar('b');
puts("");
}
else if(s[1]=='a'&&q[1]>1){
x=0;
for(int i=1;i<=tp;++i) if(q[i]==1) ++x;
if(x==tp-1){
q[1]-=1;
x-=1;
x=x%2;
if(x) q[1]-=1;
x=q[1];
}
else{
for(int i=2;i<=tp;++i){
if(q[i]>1){
q[1]=q[1]+q[i]-2;
}
}
x=x%2;
if(x) q[1]-=1;
x=q[1];
}
for(int i=1;i<=y-2;++i) putchar('b');
for(int i=1;i<=x;++i) putchar('a');
puts("");
}
else{
sort(q+1,q+1+tp);x=0;
for(int i=1;i<=tp;++i) if(q[i]==1) ++x;
if(x==tp){
x=1;
}
else{
for(int i=1;i<tp;++i) if(q[i]>1){
q[tp]=q[tp]+q[i]-2;
}
x=x%2;
if(x) q[tp]--;
x=q[tp];
}
for(int i=1;i<=y-2;++i) putchar('b');
for(int i=1;i<=x;++i) putchar('a');
puts("");
}
}
return;
}
}
int main(){
int ttt;cin>>ttt;
while(ttt--) MAIN();
return 0;
}
F Social Distance
链接
https://atcoder.jp/contests/arc113/tasks/arc113_f
题意
给n+1个数(x_0,x_1...x_n),现有n个区间([x_0,x_1],[x_1,x_2],[x_2,x_3]..[x_{n-1},x_n])。
在每个区间随机选一个实数,问这n个数最小的距离的期望值。
(nleq 20)
题解
好神的期望题。。。题解看了一整天。。
首先设(f(z))为最小距离不小于z的概率。
如果我们知道了(f(z))关于(z)的函数,那么期望值积分一下就算出来了。
于是问题转化为对于固定值(z),怎么求函数。
定义n个区间([x_0,x_1],[x_1-z,x_2-z],[x_2-2z,x_3-2z]..[x_{n-1}-(n-1)z,x_n-(n-1)z])。
原问题答案不小于(z)相当于在这n个区间选n个数,并且单调不下降。
这个新的问题可以DP。
先把n个区间转化为2n个边界,按顺序排好,(v_1,v_1,v_2,...,v_{2n})。
令(dp(i,j,k))表示dp完前i个数,其中最后k个在[v_j,v_{j+1}]区间里,并且满足不下降
考虑一个转移是(dp(i,j,k)->dp(i+1,j,k+1)),显然就是(dp(i+1,j,k+1)+=dp(i,j,k)*frac{v_{j+1}-v_j}{x_{i+1}-x_{i}}*frac{1}{k+1})
我们需要的就是最后的(sum_{0leq k leq n}dp(n,2n,k))。
每个(x_{i+1}-x_{i})都是已知的确定值,是常数。(v_{j+1}-v_j)可以写作关于(z)的一次多项式。
于是最后的答案一定是一个关于(z)的多项式。
但dp过程跟v的顺序有关,也就是每种顺序都得dp一次,这是个分段函数,段数是(O(n^2))级别的。
然后dp的时候我们直接设(F_i)为dp完前i个数之后的多项式。
于是枚举2n个边界,并枚举在这个区间内放k个数,就相当于多项式乘上k次一个关于z的一次多项式,然后除(k!)。
暴力转移即可,最后把(F_n)在可行的z的范围内做积分即可。总效率(O(n^6))。
(Code)
#include <bits/stdc++.h>
#define LL long long
#define LD long double
using namespace std;
const LL P=998244353;
const int N=3e5+10;
const int INF=1e9;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void print(LL x){
if(x>9) print(x/10);
putchar(x%10+'0');
}
void pls(LL &x,LL y){
x+=y;if(x>=P)x-=P;
}
LL qpow(LL x,LL y){
LL re=1;
while(y){
if(y&1) re=re*x%P;
x=x*x%P;y>>=1;
}
return re;
}
int n,tot;
LL X[50],L[50],R[50];
int p[50];
LL f[50][50],g[50];
LL inv[50];
int l[50],r[50];
struct node{
LL x,y;
LL U,D;
}a[2000];
bool cmp(node x,node y){
return x.U*y.D<x.D*y.U;
}
int d0[50],d1[50];
void MAIN(){
inv[0]=inv[1]=1;
for(LL i=2;i<=40;++i)inv[i]=(P-P/i)*inv[P%i]%P;
for(LL i=2;i<=40;++i)inv[i]=inv[i-1]*inv[i]%P;
scanf("%d",&n);
for(int i=0;i<=n;++i) scanf("%lld",&X[i]);
for(int i=1;i<=n;++i) {
L[i]=X[i-1];R[i]=X[i];
}
tot=0;
for(int i=1;i<=n;++i)
for(int j=1;j<i;++j)
for(int k1=0;k1<=1;++k1)
for(int k2=0;k2<=1;++k2){
++tot;
a[tot].x=i+k1*n;
a[tot].y=j+k2*n;
a[tot].U=(k1?R[i]:L[i])-(k2?R[j]:L[j]);
a[tot].D=i-j;
}
sort(a+1,a+1+tot,cmp);
p[0]=0;
for(int i=1;i<=n;++i){
p[++p[0]]=i;
p[++p[0]]=i+n;
}
LL ans=0;
for(int now=1;now<tot;++now){
int flag=0;
for(int i=1;i<=n*2;++i) if(p[i]==a[now].x){
for(int j=i+1;j<=n*2;++j) if(p[j]==a[now].y) flag=1;
if(flag) break;
for(int j=i;j<n*2;++j) p[j]=p[j+1];
break;
}
if(!flag){
for(int i=1;i<n*2;++i) if(p[i]==a[now].y){
for(int j=n*2;j>i;--j) p[j]=p[j-1];
p[i]=a[now].x;
break;
}
}
if(a[now].U*a[now+1].D==a[now+1].U*a[now].D) continue;
for(int i=1;i<=n*2;++i) if(p[i]<=n) l[p[i]]=i;else r[p[i]-n]=i;
for(int i=2;i<=n;++i) l[i]=max(l[i],l[i-1]);
for(int i=n-1;i>=1;--i) r[i]=min(r[i],r[i+1]);
flag=0;
for(int i=1;i<=n;++i) if(l[i]>=r[i]) {flag=1;break;}
if(flag) break;
memset(d0,0,sizeof(d0));
memset(d1,0,sizeof(d1));
for(int i=1;i<=n;++i){
d0[l[i]]=max(d0[l[i]],i);
d1[r[i]]=max(d1[r[i]],i);
}
memset(f,0,sizeof(f));f[0][0]=1;
int st=1,ed=0;
for(int i=1;i<n*2;++i){
ed=max(ed,d0[i]),st=max(st,d1[i]+1);
if(ed<st) continue;
for(int j=ed-1;j>=st-1;--j){
memcpy(g,f[j],sizeof(g));
LL u=(p[i]<=n?p[i]:p[i]-n)-(p[i+1]<=n?p[i+1]:p[i+1]-n);
LL v=(p[i+1]<=n?L[p[i+1]]:R[p[i+1]-n])-(p[i]<=n?L[p[i]]:R[p[i]-n]);
u=(u%P+P)%P;
v=(v%P+P)%P;
for(int k=1;k<=ed-j;++k) {
for(int t=j+k;t>=1;--t) g[t]=(g[t]*v+g[t-1]*u)%P;
g[0]=g[0]*v%P;
for(int t=0;t<=j+k;++t) pls(f[j+k][t],g[t]*inv[k]%P);
}
}
}
LL x=a[now].U*qpow(a[now].D,P-2)%P;
LL y=a[now+1].U*qpow(a[now+1].D,P-2)%P;
for(int i=0;i<=n;++i)
pls(ans,f[n][i]*qpow((LL)(i+1),P-2)%P*(qpow(y,(LL)(i+1))-qpow(x,(LL)(i+1))+P)%P);
}
for(int i=1;i<=n;++i) ans=ans*qpow(X[i]-X[i-1],P-2)%P;
printf("%lld
",ans);
return;
}
int main(){
int ttt=1;
while(ttt--) MAIN();
return 0;
}