21牛客多校第十场
A
先不考虑空间的限制,考虑每次一个字符串转变的情况,需要找到\(trie\)树上第一个独立于剩余字符串的前缀
则这个前缀即为这次所需的前缀,但需要考虑这个前缀可以替代之前的前缀的情况
新开一个\(num\)数组记录\(trie\)树上每个节点在前缀中出现了几次,则每次新增答案为找到节点的\(1-num[x]\)
再向上更新链上所有点的\(num\)即可
在空间限制下只需要将\(trie\)树的边压缩,在边上存储字符串,加入新字符串的时候考虑分裂一条边的情况
#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 250010
#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
#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,fst[MAXN],tot=1,rt=1,cnt,sum[MAXN],num[MAXN],ans;
char ch[MAXN][105];
struct Edge{int nxt,to,len;char s[105];}e[MAXN];
void add(int u,int v,char *s,int len)
{
e[++cnt].nxt=fst[u],fst[u]=cnt,e[cnt].to=v;
rep(i,0,len-1) e[cnt].s[i]=s[i];e[cnt].len=len;
}
void ins(int p,int cur,int len,int id)
{
sum[p]++;static int pos,v,lasl;
for(int i=fst[p];i;i=e[i].nxt) if(e[i].s[0]==ch[id][cur])
{
pos=-1;rep(j,0,min(len-cur-1,e[i].len-1))
if(e[i].s[j]!=ch[id][cur+j]) {pos=j;break;}
if(pos<0) {ins(e[i].to,cur+e[i].len,len,id);return ;}
v=e[i].to,lasl=e[i].len;e[i].len=pos;
e[i].to=++tot;sum[tot]=sum[v];
add(tot,v,e[i].s+pos,lasl-pos);
ins(tot,cur+pos,len,id);return ;
}
v=++tot;sum[v]++;add(p,v,ch[id]+cur,len-cur);
}
int query(int p,int cur,int len,int id)
{
if(p!=rt) sum[p]--;if(!sum[p]) {return 1-num[p];}
for(int i=fst[p],res;i;i=e[i].nxt) if(e[i].s[0]==ch[id][cur])
{res=query(e[i].to,cur+e[i].len,len,id);num[p]+=res;return res;}
}
int main()
{
n=read();int len;
rep(i,1,n) {scanf("%s",ch[i]);len=strlen(ch[i]);ins(rt,0,len,i);}
rep(i,1,n)
{
len=strlen(ch[i]);ans+=query(rt,0,len,i);
printf("%d\n",ans);
}
}
B
好像锅了 跑了
C
优化匈牙利 咕了
D
可做dp 咕了
E
大模拟 咕了
F
可以将括号序列转化为一棵树,则题目要求为每个点和它的所有兄弟颜色不同
贪心的分配颜色,将每个点按照儿子个数降序排序,每次选出可用颜色中前\(k\)大的进行分配
#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
#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,st[MAXN],tp,num[MAXN],cur,g[MAXN],ans[MAXN];
char s[MAXN<<1];
vector<int> vec[MAXN],tmp;
struct Data{int w,id;};
bool operator < (Data a,Data b){return a.w<b.w;}
priority_queue<Data> q;
bool cmp(int x,int y){return vec[x].size()>vec[y].size();}
int main()
{
n=read();scanf("%s",s+1);
rep(i,1,n<<1)
if(s[i]=='(') vec[st[tp]].pb(++cur),st[++tp]=cur;
else tp--;
rep(i,1,n) num[read()]++,g[i]=i;
rep(i,1,n) if(num[i]) q.push({num[i],i});
sort(g+1,g+n+1,cmp);int col;
rep(i,0,n) if(vec[i].size())
{
for(auto x:vec[i])
{
if(q.empty()) {puts("NO");return 0;}
col=q.top().id;q.pop();
ans[x]=col,num[col]--,tmp.pb(col);
}
for(auto x:tmp) if(num[x]) q.push({num[x],x});
tmp.clear();
}
puts("YES");
rep(i,1,n) printf("%d%c",ans[i],i==n?'\n':' ');
}
G
令\(g(S)\)表示实际射中人的集合为\(S\)子集的概率,每个人只能选择射不中或者射到集合内的人
则\(g(S)=(1-p+\frac{|S|-1}{n-1}p)^{|S|}(1-p+\frac{|S|}{n-1}p)^{n-|S|}=(1-\frac{n-|S|}{n-1}p)^{|S|}(1-\frac{n-|S|-1}{n-1}p)^{n-|S|}\)
可知当集合大小相同时答案相等即\(g(|S|)=g(S)\)
令\(f(S)\)为射中人集合恰好为\(S\)的概率,由容斥可得\(f(S)=\sum\limits_{T\subseteq S}(-1)^{|S|-|T|}g(T)=\sum\limits_{i=0}^{|S|}(-1)^{|S|-i}\binom{|S|}{i}g(i)\)
化为卷积形式即\(f(i)=i!\sum\limits_{j=0}^i\frac{(-1)^{i-j}}{(i-j)!}\cdot \frac{g(j)}{j!}\)
而\(ans_i=\binom{n}{i}f(i)=\frac{n!}{(n-i)!}\sum\limits_{j=0}^i\frac{(-1)^{i-j}}{(i-j)!}\cdot \frac{g(j)}{j!}\)
得到\(g(i)\)之后卷积即可
#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 500100
#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,p,f[MAXN<<1],g[MAXN<<1],fac[MAXN],ifac[MAXN];
int pw[30],rev[MAXN<<1],ipw[30];
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 mem(int n)
{
int lg=1,lim=1;
for(;lim<n;lim<<=1,lg++)
pw[lg]=qp(3,(MOD-1)/(1<<lg)),ipw[lg]=inv(pw[lg]);
rep(i,0,lim-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-2));
return lim;
}
void ntt(int *a,int n,int f)
{
rep(i,0,n-1) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int i=1,t=1;i<n;i<<=1,++t)
{
int wn= f>0?pw[t]:ipw[t];for(int j=0;j<n;j+=i<<1)
{
int w=1,x,y;for(int k=0;k<i;++k,w=mul(w,wn))
x=a[j+k],y=mul(a[j+k+i],w),a[j+k]=pls(x,y),a[j+k+i]=mns(x,y);
}
}
rep(i,0,n-1) a[i]=pls(a[i],MOD);if(f>0) return ;
int nv=inv(n);rep(i,0,n-1) a[i]=mul(a[i],nv);
}
int main()
{
n=read(),p=read(),p=mul(p,inv(read()));
fac[0]=1;rep(i,1,n) fac[i]=mul(fac[i-1],i);
ifac[n]=inv(fac[n]);dwn(i,n-1,0) ifac[i]=mul(ifac[i+1],i+1);
f[0]=1;rep(i,1,n) f[i]=(i&1)?mns(0,ifac[i]):ifac[i];
rep(i,0,n)
g[i]=mul(qp(mns(1,qp(n-1,MOD-2,mul(n-i,p))),i),ifac[i]),
g[i]=mul(qp(mns(1,qp(n-1,MOD-2,mul(n-i-1+MOD,p))),n-i),g[i]);
int lim=mem(n+1<<1);
ntt(f,lim,1);ntt(g,lim,1);rep(i,0,lim-1) f[i]=mul(f[i],g[i]);
ntt(f,lim,-1);
dwn(i,n,0) printf("%d\n",mul(mul(fac[n],ifac[n-i]),f[i]));
}
H
按照二进制\(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 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
#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;
int main()
{
n=read();
rep(i,0,((1<<n)-1)) putchar(__builtin_popcount(i)&1?'0':'1');
}
I
奇妙构造 咕了
J
板子题 求凸包切线+环的最小区间覆盖 咕
K
有点乱搞 咕