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
对于在凸包内的点,固定\(x\),\(y\)后均为凸函数(
三分套三分然后暴力\(check\)
#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;
}
const ld eps=1e-9,pi=acos(-1);
int n;ld xx[110],yy[110],xl=10000,xr=-10000,yl=10000,yr=-10000;
struct vec{ld x,y;}v[110];
ld operator ^ (vec &a,vec &b){return a.x*b.x+a.y*b.y;}
ld operator & (vec &a,vec &b){return a.x*b.y-a.y*b.x;}
inline ld getLen(vec &a){return sqrt(a.x*a.x+a.y*a.y);}
inline ld getAngle(vec &a,vec &b)
{
ld res=a^b;res/=getLen(a)*getLen(b);
return acos(res);
}
inline int ok(ld x,ld y)
{
rep(i,1,n) if((v[i]&v[i+1])<0-eps) return 0;
return 1;
}
inline ld cheq(ld x,ld y)
{
ld res=4;
rep(i,1,n) v[i]={xx[i]-x,yy[i]-y};v[n+1]=v[1];
if(!ok(x,y)) return -inf;
rep(i,1,n) res=min(res,getAngle(v[i],v[i+1]));
return res;
}
inline ld calc(ld x)
{
ld l=yl,r=yr,ml,mr,al,ar;
while(r-l>eps)
{
ml=(l*2+r)/3,mr=(l+r*2)/3;
al=cheq(x,ml),ar=cheq(x,mr);
if(al>ar) r=mr;else l=ml;
}
return cheq(x,(l+r)/2);
}
int main()
{
n=read();
rep(i,1,n)
xx[i]=read(),yy[i]=read(),
xl=min(xl,xx[i]),xr=max(xr,xx[i]),
yl=min(yl,yy[i]),yr=max(yr,yy[i]);
ld l=xl,r=xr,ml,mr,al,ar;
while(r-l>eps)
{
ml=(l*2+r)/3,mr=(l+r*2)/3;
al=calc(ml),ar=calc(mr);
if(al>ar) r=mr;else l=ml;
}
printf("%.10Lf\n",calc((l+r)/2)*180./pi);
}
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
考虑如下形式的矩阵,在任何情况下均满足条件:
#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\)裸题
#include<bits/stdc++.h>
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 350
#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;
}
const ll inf=213906214300000000LL;
namespace KM
{
int n,vx[MAXN],vy[MAXN],linky[MAXN],pre[MAXN];
ll slack[MAXN],dbx[MAXN],dby[MAXN],dis[MAXN][MAXN],ans;
void bfs(int k)
{
int py=0,px,yy=0;ll tmp;
linky[0]=k;Fill(slack,0x3f);Fill(pre,0);
do
{
px=linky[py],tmp=inf,vy[py]=1;
rep(i,1,n) if(!vy[i])
{
if(dbx[px]+dby[i]-dis[px][i]<slack[i])
slack[i]=dbx[px]+dby[i]-dis[px][i],pre[i]=py;
if(slack[i]<tmp) tmp=slack[i],yy=i;
}
rep(i,0,n)
if(vy[i])
dbx[linky[i]]-=tmp,dby[i]+=tmp;
else slack[i]-=tmp;
py=yy;
}while(linky[py]);
while(py) linky[py]=linky[pre[py]],py=pre[py];
}
ll solve()
{
Fill(linky,0);rep(i,1,n) {Fill(vy,0);bfs(i);}
ans=0;rep(i,1,n) ans+=dis[linky[i]][i];return ans;
}
};
int n,x[MAXN],y[MAXN],z[MAXN],v[MAXN];
ll ans;
int main()
{
n=read();KM::n=n;
rep(i,1,n) x[i]=read(),y[i]=read(),z[i]=read(),v[i]=read();
rep(i,1,n)
{
ans+=x[i]*x[i]+y[i]*y[i]+z[i]*z[i],KM::dbx[i]=-inf;
rep(j,1,n)
KM::dis[i][j]=-2*(i-1)*v[j]*z[j]-1LL*(i-1)*(i-1)*v[j]*v[j],
KM::dbx[i]=max(KM::dbx[i],KM::dis[i][j]);
}
ans-=KM::solve();
printf("%lld\n",ans);
}
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);
}
}