21牛客多校第五場
A
圓方樹 咕
B
顯然開盒子的順序應按照\(w\)升序,而\(hint\)若選擇使用應該在一開始就使用
在使用\(hint\)的情況下,因為知道\(01\)的總數,每種情況應當在最後一段連續的\(0/1\)前終止
即\(100\cdots 0\)此類情況,在\(0\)處截止,其花費為\(sum_i\)即到\(0\)處\(w\)的字首和
而此類情況的概率為後\(n-i\)一樣且第\(i\)個不同,\(p=\frac{2}{2^{n-i+1}}=\frac{1}{2^{n-i}}\)
最後比較使用\(hint\)的答案與暴力全開哪個較小
#include<bits/stdc++.h> #define inf 2139062143 #define ll long long #define db double #define ld long double #define ull unsigned long long #define MAXN 100100 #define MOD 998244353 #define Fill(a,x) memset(a,x,sizeof(a)) #define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i) #define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i) #define ren for(int i=fst[x];i;i=nxt[i]) #define pls(a,b) (a+b)%MOD #define mns(a,b) (a-(b)+MOD)%MOD #define mul(a,b) (1LL*(a)*(b))%MOD #define pii pair<int,int> #define fi first #define se second #define pb push_back using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} return x*f; } int n;db x,w[MAXN],ans; int main() { n=read();scanf("%lf",&x); rep(i,1,n) scanf("%lf",&w[i]); sort(w+1,w+n+1);rep(i,1,n) w[i]+=w[i-1]; db pw=0.5; dwn(i,n-1,1) ans+=w[i]*pw,pw*=0.5; ans=min(ans+x,w[n]); printf("%.7lf\n",ans); }
C
由於調和級數,需要\(O(1)\)查詢對\(i=t\)的情況終止點在哪裡
考慮先預處理每個位置的\(W,L\)字首和以及每個\(W,L\)位置,這樣可以找到從位置\(x\)開始後先到\(i\)球的位置
若此時\(W,L\)的差\(>1\)則顯然勝負已分,否則需要處理一個從每個點開始何時破局,設為\(nxt_x\)
對位置\(x\)來說,若接下來是兩球不同,則仍然是平局,\(nxt_x=nxt_{x+2}\);否則在\(x+1\)時刻該局結束
預處理完畢後模擬
#include<bits/stdc++.h> #define inf 2139062143 #define ll long long #define db double #define ld long double #define ull unsigned long long #define MAXN 1001001 #define MOD 998244353 #define Fill(a,x) memset(a,x,sizeof(a)) #define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i) #define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i) #define ren for(int i=fst[x];i;i=nxt[i]) #define pls(a,b) (a+b)%MOD #define mns(a,b) (a-(b)+MOD)%MOD #define mul(a,b) (1LL*(a)*(b))%MOD #define pii pair<int,int> #define fi first #define se second #define pb push_back using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} return x*f; } int n,cnt[MAXN][2],pos[MAXN][2],nxt[MAXN],ans; char s[MAXN]; int main() { n=read();scanf("%s",s+1); rep(i,1,n) { rep(j,0,1) cnt[i][j]=cnt[i-1][j]; if(s[i]=='L') pos[++cnt[i][0]][0]=i; else pos[++cnt[i][1]][1]=i; } nxt[n]=nxt[n+1]=n+1; dwn(i,n-1,1) nxt[i]= s[i]==s[i+1]?i+1:nxt[i+2]; int p1,p2,p,c1,c2,pw=1,res; rep(t,1,n) { res=0;rep(i,0,n) { p1=p2=n+1; if(cnt[i][0]+t<=cnt[n][0]) p1=pos[cnt[i][0]+t][0]; if(cnt[i][1]+t<=cnt[n][1]) p2=pos[cnt[i][1]+t][1]; p=min(p1,p2);if(p==n+1) break; c1=cnt[p][0]-cnt[i][0],c2=cnt[p][1]-cnt[i][1]; if(abs(c1-c2)==1) p=nxt[p]; if(p==n+1) break; c1=cnt[p][0]-cnt[i][0],c2=cnt[p][1]-cnt[i][1]; res+=(c1<c2);i=p-1; } ans=pls(ans,mul(res,pw)),pw=mul(pw,n+1); } printf("%d\n",ans); }
D
可以在每次找到一對相同\(a_i=b_j\)時統計答案,設\(f[i][j]\)表示前面範圍內以\(i,j\)結尾的公共子序列個數,\(g[i][j]\)表示後面範圍內符合條件的點對個數
\(f[i][j]\)簡單\(dp\)即可,\(g[i][j]\)的計算過程中,每次找到一對符合答案的\(a_i<b_j\)需要\(+\sum\limits_{i=0}^{min(x,y)} \binom{x}{i}\binom{y}{i}\)這樣的東西
不妨令\(x\le y\) 有\(\sum\limits_{i=0}^{x} \binom{x}{i}\binom{y}{i}=\sum\limits_{i=0}^{x} \binom{x}{x-i}\binom{y}{i}=\sum\limits_{i=0}^{x} \binom{x+y}{x}\)
預處理階乘後直接\(dp\)
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 1000000007
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b)+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,dp[5050][5050],f[5050][5050];
int fac[MAXN],ifac[MAXN],ans;
char a[5050],b[5050];
int qp(int x,int t,int res=1)
{
for(;t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);
return res;
}
#define inv(x) qp(x,MOD-2)
int C(int n,int m)
{
return mul(fac[n],mul(ifac[n-m],ifac[m]));
}
int main()
{
scanf("%s%s",a+1,b+1);n=strlen(a+1),m=strlen(b+1);
ifac[0]=fac[0]=1;rep(i,1,1e4+10) fac[i]=mul(fac[i-1],i),ifac[i]=inv(fac[i]);
dwn(i,n,1) dwn(j,m,1)
{
f[i][j]=mns(pls(f[i][j+1],f[i+1][j]),f[i+1][j+1]);
if(a[i]<b[j]) f[i][j]=pls(f[i][j],C(m-j+n-i,m-j));
}
ans=f[1][1];
rep(i,1,n) rep(j,1,m)
{
if(a[i]==b[j])
{
dp[i][j]=pls(dp[i-1][j-1],1);
ans=pls(ans,mul(dp[i][j],f[i+1][j+1]));
}
dp[i][j]=pls(mns(pls(dp[i-1][j],dp[i][j-1]),dp[i-1][j-1]),dp[i][j]);
}
printf("%d\n",ans);
}
E
樹\(dp\) 咕
F
三分套三分 咕
G
設\(F_S\)表示該位為\(1\)的質因數取滿其餘隨意組合出的數和\(a\)的最小差,\(G_S\)表示和\(b\)的差,答案即為所有\(F_{i}+G_{U-i}\)取\(min\)
而搜尋的時候可以搜尋出: 該位為\(1\)的質因數取滿其餘不取滿組合出的數和\(a\)的最小差,記為\(f_S\)
令\(F=f\),\(F_S\)可以更新所有\(F_{S-(1<<j)}\),\(O(n2^n)\)計算出所有\(F\),\(G\)同理
最後統計答案
#include<bits/stdc++.h>
#define inf 2139062143
#define ll __int128
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b)+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void write(ll x)
{
int st[40],tp=0;
if(!x) {putchar('0');return ;}
while(x) st[++tp]=x%10,x/=10;
while(tp) putchar(st[tp--]+'0');
}
int n;ll w[20],tot[20],a,b;
ll f[1<<18],g[1<<18],ans;
void dfs(int x,int st,ll now)
{
if(x==n+1)
{
if(now>=a) f[st]=min(f[st],now-a);
if(now>=b) g[st]=min(g[st],now-b);
return ;
}
dfs(x+1,st,now);
rep(i,1,tot[x]-1) {now*=w[x];dfs(x+1,st,now);}
now*=w[x],st|=(1<<x-1);dfs(x+1,st,now);
}
int main()
{
n=read();rep(i,1,n) w[i]=read(),tot[i]=read();
a=read(),b=read(),ans=1;
int mxs=(1<<n)-1;rep(i,1,33) ans=ans*10;
rep(i,0,mxs) f[i]=g[i]=ans;dfs(1,0,1);
dwn(i,mxs,0) rep(j,0,n-1) if(!((i>>j)&1))
f[i]=min(f[i|(1<<j)],f[i]),g[i]=min(g[i|(1<<j)],g[i]);
rep(i,0,mxs) ans=min(ans,f[i]+g[mxs^i]);
write(ans);
}
H
考慮如下形式的矩陣,在任何情況下均滿足條件:
\[\begin{pmatrix} 0&1&0&1&0&\cdots\\ 0&1&0&1&0&\cdots\\ 1&0&1&0&1&\cdots\\ 1&0&1&0&1&\cdots\\ \vdots&\vdots&\vdots&\vdots&\vdots&\ddots \end{pmatrix} \]#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b)+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m;
int main()
{
n=read(),m=read();
rep(i,0,n-1) {rep(j,0,m-1) printf("%d",(i/2+j)&1);puts("");}
}
I
還挺裸的回滾莫隊,用連結串列維護一下每個區間的左右端點,每次更新答案總複雜度\(O(n\sqrt{n}+k)\)
回滾莫隊時可以把一個更改操作的指標和值一起放到\(vector\)裡,寫起來非常方便
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b)+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void inc(int &x,int y){x=pls(x,y);}
int n,Q,sz,g[MAXN],bl[MAXN],ans[MAXN],cnt[MAXN],res,l[MAXN],r[MAXN];
vector<pair<int*,int> > opt;
struct Ask{int id,l,r,k;}q[MAXN];
bool operator < (Ask &a,Ask &b){return bl[a.l]==bl[b.l]?a.r<b.r:a.l<b.l;}
inline void mdf(int *x,int w){opt.pb({x,*x});*x=w;}
inline void add(int x)
{
if(cnt[g[x]]) return ;x=g[x];mdf(&cnt[x],1);
//cout<<"add: "<<x<<endl;
int pre=l[x-1],suf=r[x+1];
if(pre==-1) pre=x;if(suf==-1) suf=x;
mdf(&r[pre],suf);mdf(&l[suf],pre);
if(suf-pre+1>res) mdf(&res,suf-pre+1);
}
void del(int t)
{
while(opt.size()>t)
{*opt.back().fi=opt.back().se;opt.pop_back();}
}
int main()
{
n=read(),Q=read(),sz=sqrt(n+5);Fill(l,0xff);Fill(r,0xff);
rep(i,1,n) g[i]=read(),bl[i]=i/sz;
rep(i,1,Q) q[i].l=read(),q[i].r=read(),q[i].k=read()-1,q[i].id=i;
sort(q+1,q+Q+1);int ed,pos,tag,pw;
rep(i,1,Q)
{
if(i==1||bl[q[i].l]!=bl[q[i-1].l])
{ed=bl[q[i].l]*sz+sz,pos=ed+1;del(0);}
rep(j,pos,q[i].r) add(j);if(q[i].r>=pos) pos=q[i].r+1;tag=opt.size();
dwn(j,min(ed,q[i].r),q[i].l) add(j);
pw=1;inc(ans[q[i].id],res);
rep(j,1,q[i].k)
{
pw=mul(pw,n+1);add(q[i].l-j);add(q[i].r+j);
inc(ans[q[i].id],mul(res,pw));
}
del(tag);
}
rep(i,1,Q) printf("%d\n",ans[i]);
}
J
KM 咕
K
考慮對於每個左端點\(l\)找到一個\(r\)使得\([l,r]\)符合條件,則\([l,r+1],\dots [l,n]\)這些區間均符合條件
容易發現當\(l\)右移時,\(r\)也一定右移,不可能左移;因此可以使用滑動視窗
對於區間內的最大值與最小值,可以用單調佇列維護
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b)+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,k,mn[MAXN],mx[MAXN],g[MAXN],h1,t1,h2,t2;
ll ans;
int main()
{
n=read(),m=read();rep(i,1,n) g[i]=read();
rep(t,1,m)
{
k=read();h1=h2=1,t1=t2=0;ans=0;int l=1;
rep(i,1,n)
{
while(h1<=t1&&g[mx[t1]]<=g[i]) t1--;mx[++t1]=i;
while(h2<=t2&&g[mn[t2]]>=g[i]) t2--;mn[++t2]=i;
while(h1<=t1&&h2<=t2&&g[mx[h1]]-g[mn[h2]]>k)
{
ans+=n-i+1,l++;
if(mx[h1]<l) h1++;
if(mn[h2]<l) h2++;
}
}
printf("%lld\n",ans);
}
}