21牛客多校第四场

A

很猛的生成函数 咕

B

不妨考虑将题意转化为图,设\(0\)为起始点,\(n+1\)为终止点

假设当前在\(i\)点,下一次生成的数需要更大才能继续,即每次可以走到\(i+1,\dots n\)这些点

而对于生成更小数的情况则代表了结束,对这种情况我们对\(i\)\(n+1\)连这些概率的边代表结束

\(f_i\)表示到从\(i\)走到\(n+1\)的步数期望,\(g_i\)表示从\(i\)走到\(n+1\)的步数平方的期望,最终要求的即为\(g_0\)

显然可以得到\(f_i=\sum\limits_{j=i}^{n+1} p_{i\rightarrow j}(f_j+1)\),其中\(p_{i\rightarrow j}\)表示从\(i\)走到\(j\)的概率

将右侧的\(f_i\)移动到等式左边即可得到\(f_i\)从后向前的递推式,\((1-p_{i\rightarrow i})f_i=\sum\limits_{j=i+1}^{n+1}(f_j+1)\)

考虑\(g_i\)的转移,\(g_i=\sum\limits_{j=i}^{n+1}p_{i\rightarrow j}E[(L_j+1)^2]\),其中\(L_j\)表示到\(j\)还需走几步

\(E[(x+1)^2]\)具体表示,得:

\[\begin{aligned} E[(x+1)^2]&=\sum\limits_{i=0}^{\infty}p_i(i+1)^2\\ &=\sum\limits_{i=0}^{\infty}p_i(i^2+2i+1)\\ &=\sum\limits_{i=0}^{\infty}p_i\cdot i^2+2\sum\limits_{i=0}^{\infty}p_i\cdot i+\sum\limits_{i=0}^{\infty}p_i\\ &=E[x^2]+2E[x]+1 \end{aligned} \]

\(E[(L_j+1)^2]=E[L_j^2]+2E[L_j]+1=g_j+2f_j+1\)

\(g_i=\sum\limits_{j=i}^{n+1}p_{i\rightarrow j}(g_j+2f_j+1)\),同样将右侧的\(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 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;
}
ll n,f[110],g[110],p[110];
ll qp(ll x,ll t)
{
	ll 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 main()
{
	n=read();int s=0,pp;rep(i,1,n) p[i]=read(),s+=p[i];
	s=inv(s);rep(i,1,n) p[i]=mul(p[i],s);
	f[n+1]=g[n+1]=0;
	dwn(i,n,0)
	{
		s=pp=0;rep(j,1,i-1) pp=pls(p[j],pp);p[n+1]=pp;
		rep(j,i+1,n+1) s=pls(s,mul(p[j],f[j]+1));
		f[i]=mul(pls(s,p[i]),inv(mns(1,p[i])));
	}
	dwn(i,n,0)
	{
		s=pp=0;rep(j,1,i-1) pp=pls(p[j],pp);p[n+1]=pp;
		rep(j,i,n+1) s=pls(s,mul(p[j],pls(g[j]+1,mul(2,f[j]))));
		g[i]=mul(s,inv(mns(1,p[i])));
	}
	printf("%lld\n",g[0]);
}

C

不妨令\(c<a\le b\),考虑这样一种构造

\(s1=\underbrace{a\dots a}_{a个}\ \underbrace{b\dots b}_{b-a个}\ \underbrace{c\dots c}_{c-a个}\ \underbrace{d\dots d}_{剩余补位}\)

\(s2=\underbrace{a\dots a}_{a个}\ \underbrace{b\dots b}_{剩余补位}\)

\(s3=\underbrace{a\dots a}_{a个}\ \underbrace{c\dots c}_{剩余补位}\)

这种构造已经用了最少的字符,当\(a+(b-a)+(c-a)> n\)时无解,其余情况有解

#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 a,b,c,n;char s[5][1010];
int main()
{
	a=read(),b=read(),c=read(),n=read();
	int mn=min(min(a,b),c);if(mn+a-mn+b-mn+c-mn>n) return puts("NO"),0;
	rep(i,1,mn) s[1][i]=s[2][i]=s[3][i]='a';
	a-=mn,b-=mn,c-=mn;
	if(!a)
	{
		rep(i,mn+1,n) s[1][i]='b',s[2][i]='c';
		rep(i,mn+1,mn+b) s[3][i]='c';
		rep(i,mn+b+1,mn+b+c) s[3][i]='b';
		rep(i,mn+b+c+1,n) s[3][i]='x';
	}
	if(!b)
	{
		rep(i,mn+1,n) s[2][i]='b',s[3][i]='c';
		rep(i,mn+1,mn+a) s[1][i]='b';
		rep(i,mn+a+1,mn+a+c) s[1][i]='c';
		rep(i,mn+a+c+1,n) s[1][i]='x';
	}
	if(!c)
	{
		rep(i,mn+1,n) s[1][i]='b',s[3][i]='c';
		rep(i,mn+1,mn+b) s[2][i]='c';
		rep(i,mn+b+1,mn+b+a) s[2][i]='b';
		rep(i,mn+b+a+1,n) s[2][i]='x';
	}
	printf("%s\n%s\n%s\n",s[1]+1,s[2]+1,s[3]+1);
}

D

求原题的方案数等价于求将树分成\(k+1\)个联通块再求生成树的数量

对于\(s_1,s_2,\dots,s_{k+1}\)\(k+1\)个联通块,考虑\(prufer\)序列有\(n^{k-1}\)种,而每次连边的时候还要从联通块里选一个连边,答案即为\(n^{k-1}\cdot s_1\cdot s_2\cdots s_{k+1}\)

后面的连乘式并不好计算,转化成对于整个树删了\(k\)条边且每个联通块内选一个点的方案数

\(dp[i][j][0/1]\)表示节点\(i\)的子树内选了\(j\)个联通块,\(i\)所在联通块是否选择过点

\(dp\)方程显然,\(dp[x][i],dp[v][j]\)可以转移到\(dp[x][i+j],dp[x][i+j-1]\)\(O(nk)\ 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 50100
#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,k,dp[MAXN][120][2],nxt[MAXN<<1],to[MAXN<<1],fst[MAXN],cnt,sz[MAXN];
void inc(int &x,int y) {x=pls(x,y);}
void add(int u,int v){nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;}
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;
}
int tmp[120][2],ans;
void dfs(int x,int pa)
{
	sz[x]=1;dp[x][1][1]=dp[x][1][0]=1;int v;
	ren if(to[i]^pa)
	{
		v=to[i];dfs(v,x);Fill(tmp,0);
		dwn(i,min(sz[x],k+1),1) dwn(j,min(sz[v],k+2-i),1)
			inc(tmp[i+j-1][0],mul(dp[x][i][0],dp[v][j][0])),
			inc(tmp[i+j-1][1],mul(dp[x][i][1],dp[v][j][0])),
			inc(tmp[i+j-1][1],mul(dp[x][i][0],dp[v][j][1])),
			inc(tmp[i+j][0],mul(dp[x][i][0],dp[v][j][1])),
			inc(tmp[i+j][1],mul(dp[x][i][1],dp[v][j][1]));
		sz[x]+=sz[to[i]];
		rep(j,1,min(sz[x],k+1)) dp[x][j][0]=tmp[j][0],dp[x][j][1]=tmp[j][1];
	}
}
int main()
{
	n=read(),k=read();int a,b;
	rep(i,2,n) a=read(),b=read(),add(a,b),add(b,a);
	dfs(1,0);ans=qp(n,k-1,dp[1][k+1][1]);
	printf("%d\n",ans);
}

E

对于这棵树,如果有一个点的值被确定则所有点的值都被确定

考虑通过\(2,\cdots,n\)这些点来找到\(1\)的取值范围

预处理出所有点到\(1\)的异或距离\(dis_i\),则对于\(i\)点的限制,\(1\)点的合法选择是\(j\otimes dis_i,\ l_i\le j\le r_i\)

对于\([1,r_i]\)区间内的所有数,每次异或一个值相当于交换一次子树,而这些数构成的\(trie\)树从左至右是满的

因此对于每一位都有一段连续的区间的数满足条件,用动态开点线段树维护

最后查询线段树上有多少个点被加了\(n-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)%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,l[MAXN],r[MAXN],nxt[MAXN<<1],to[MAXN<<1],val[MAXN<<1],fst[MAXN],Cnt;
int dis[MAXN];
void add(int u,int v,int w) {nxt[++Cnt]=fst[u],fst[u]=Cnt,to[Cnt]=v,val[Cnt]=w;}
const int lim=(1<<30)-1;
int rt,tot,ls[MAXN<<6],rs[MAXN<<6],cnt[MAXN<<6],mx[MAXN<<6],tag[MAXN<<6],ans;
inline void pshd(int k,int l,int r,int mid)
{
	if(!ls[k]) ls[k]=++tot,mx[tot]=0,cnt[tot]=mid-l+1;
	if(!rs[k]) rs[k]=++tot,mx[tot]=0,cnt[tot]=r-mid;
	tag[ls[k]]+=tag[k],tag[rs[k]]+=tag[k];
	mx[ls[k]]+=tag[k],mx[rs[k]]+=tag[k],tag[k]=0;
}
inline void upd(int k)
{
	mx[k]=cnt[k]=0;
	if(ls[k]) mx[k]=max(mx[k],mx[ls[k]]);
	if(rs[k]) mx[k]=max(mx[k],mx[rs[k]]);
	if(ls[k]) cnt[k]+=cnt[ls[k]]*(mx[ls[k]]==mx[k]);
	if(rs[k]) cnt[k]+=cnt[rs[k]]*(mx[rs[k]]==mx[k]);
}
void mdf(int &k,int l,int r,int a,int b,int w)
{
	if(!k) k=++tot,mx[k]=0,cnt[k]=r-l+1;
	if(a<=l&&r<=b) {tag[k]+=w,mx[k]+=w;return ;}
	int mid=l+r>>1;if(tag[k]) pshd(k,l,r,mid);
	if(a<=mid) mdf(ls[k],l,mid,a,b,w);
	if(b>mid) mdf(rs[k],mid+1,r,a,b,w);
	upd(k);
}
int query(int k,int l,int r,int a,int b,int w)
{
	if(!k) return 0;
	if(a<=l&&r<=b) return (mx[k]==w)*cnt[k];
	int mid=l+r>>1,res=0;if(tag[k]) pshd(k,l,r,mid);
	if(a<=mid) res=query(ls[k],l,mid,a,b,w);
	if(b>mid) res+=query(rs[k],mid+1,r,a,b,w);
	return res;
}
int tmp[50];
void calc(int t,int v)
{
	if(t<0) return ;
	int w=0;dwn(i,29,0) if((t>>i)&1)
	{
		if(!tmp[i]) {mdf(rt,0,lim,w,w+(1<<i)-1,v);w+=(1<<i);}
		else mdf(rt,0,lim,w+(1<<i),w+(1<<i+1)-1,v);
	}
	else if(tmp[i]) w+=(1<<i);
	mdf(rt,0,lim,w,w,v);
}
void work(int x)
{
	dwn(i,29,0) if((dis[x]>>i)&1) tmp[i]=1;else tmp[i]=0;
	calc(r[x],1);calc(l[x]-1,-1);
}
void dfs(int x,int pa)
{
	if(x!=1) work(x);
	ren if(to[i]^pa) {dis[to[i]]=dis[x]^val[i];dfs(to[i],x);}
}
int main()
{
	n=read();rep(i,1,n) l[i]=read(),r[i]=read();int a,b,c;
	rep(i,2,n) a=read(),b=read(),c=read(),add(a,b,c),add(b,a,c);
	dfs(1,0);ans=query(rt,0,lim,l[1],r[1],n-1);
	printf("%d\n",ans);
}

F

由于删除联通块的时候联通块不能有环,显然可以考虑两人先顺次删掉所有非树边

对于剩下的若干个森林,继续删边使联通块个数\(+1\),删除联通块使联通块个数\(-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 3001001
#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,fa[MAXN],m,totn,tote;
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int main()
{
	n=totn=read(),m=read();rep(i,1,n) fa[i]=i;int a,b;
	rep(i,1,m) 
	{
		a=read(),b=read();
		if(find(a)!=find(b)) totn--,fa[find(a)]=find(b);
		else tote++;
	}
	printf((1&(tote+totn))?"Alice":"Bob");
}

G

先不考虑\(k\),我们有结论:

\[\sum_{a_i\ge 0,\sum_{i=1}^na_i = D} \prod_{i=1}^n \frac{1}{a_i!} = \frac{n^D}{D!} \]

可以用二项式定理证明

对于题目来说,可以做如下转化:

\[\begin{aligned} Ans&=D!\sum_{a_i\ge 0,\sum_{i=1}^na_i = D} \prod_{i=1}^n \frac{1}{(a_i+k)!}\\ &=D!\sum_{a_i\ge k,\sum_{i=1}^na_i = D+nk} \prod_{i=1}^n \frac{1}{a_i!} \end{aligned} \]

不考虑范围限制,有:

\[Ans=D!\sum_{a_i\ge 0,\sum_{i=1}^na_i = D+nk} \prod_{i=1}^n \frac{1}{a_i!} = \frac{n^{D+nk}}{(D+nk)!}D! \]

需要容斥,考虑有至少\(t\)个数\(<k\)时的贡献:

\[D! \cdot \ \binom{n}{t}(-1)^t\sum_{0<a_i<k} \prod\limits_{i=1}^t\frac{1}{a_i}\cdot \sum_{a_i\ge 0,\sum_{i=1}^na_i= D+nk} \prod_{i=t+1}^n \frac{1}{a_i!} \\ =D! \cdot \ \binom{n}{t}(-1)^t\sum_{0<a_i<k} \prod\limits_{i=1}^t\frac{1}{a_i}\cdot \lgroup \frac{(n-t)^{D+nk-a_1-\dots-a_t}}{(D+nk-a_1-\dots-a_t)!}\rgroup \]

\(f[i][j]\)表示有\(i\)个数每个\(<k\)总和为\(j\)时的贡献即\(\sum_{0<a_i<k,\sum_{i=1}^t a_i=j} \prod\limits_{i=1}^t\frac{1}{a_i}\)

可以\(O(n^2k^2)\)简单\(dp\)转移得到

为方便计算,可以继续化简一下贡献:

\[D! \cdot \ \binom{n}{t}(-1)^t\cdot f[i][j]\cdot \frac{(n-t)^{D+nk-j}}{(D+nk-j)!}\\ =\frac{D!}{(D+nk)!}\binom{n}{t}(-1)^t\cdot f[i][j]\cdot (n-t)^{D+nk-j}\prod_{i=D+nk-j+1}^{D+nk}i \]

这样在枚举\((i,j)\)时可以记录后面的连乘积,最后再计算前面的\(\frac{D!}{(D+nk)!}\)\(\prod\limits_{i=D+1}^{D+nk}\frac{1}{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 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,f[3000][3000],fac[3000],ifac[3000],ans;
const int lim=2550;
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)
inline int C(int n,int m)
{
	if(n<0||m<0||n<m) return 0;
	return mul(fac[n],mul(ifac[m],ifac[n-m]));
}
int main()
{
	n=read(),k=read(),m=read();int c,tmp;
	fac[0]=1;rep(i,1,lim) fac[i]=mul(fac[i-1],i);
	ifac[lim]=inv(fac[lim]);dwn(i,lim-1,0) ifac[i]=mul(ifac[i+1],i+1);
	f[0][0]=1;rep(i,1,n) rep(j,0,i*(k-1)) rep(o,0,min(k-1,j))
		f[i][j]=pls(f[i][j],mul(f[i-1][j-o],ifac[o]));
	rep(i,0,n) rep(j,0,i*(k-1))
	{
		c=C(n,i);if(i&1) c=MOD-c;if(!j) tmp=1;
		ans=pls(ans,mul(mul(c,tmp),mul(f[i][j],qp(n-i,m+n*k-j))));
		tmp=mul(tmp,m+n*k-j);
	}
	rep(i,m+1,m+n*k) ans=mul(ans,inv(i));printf("%d\n",ans);
}

H

题目中\(x\otimes y=\frac{ab}{gcd(a,b)^2}=\frac{a}{gcd(a,b)}\cdot \frac{b}{gcd(a,b)}\),即可设\(x=i\cdot k,y=j\cdot k,(i,j)=1\)

\(b_{x\otimes y}=b_{ij}=\sum_{k=1}^{\lfloor \frac{n}{max(i,j)}\rfloor } a_{ik}\cdot (jk)^c=\sum_{k=1}^{\lfloor \frac{n}{max(i,j)}\rfloor } a_{ik}\cdot k^c\cdot j^c\)

考虑枚举\(i\),则可设\(sum_m=\sum\limits_{k=1}^m a_{ij}\cdot j^c\)

由于枚举\((i,j)\)是调和级数即\(nlogn\)级别的,对于每个\((i,j)\)可以通过\(sum\)\(O(1)\)计算,即\(b_{ij}+=j^c\cdot sum[{\lfloor \frac{n}{max(i,j)}\rfloor}]\)

#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,c,g[MAXN],h[MAXN],ans,b[MAXN],s[MAXN];
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
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;
}
int main()
{
	n=read(),c=read();int tmp;
	rep(i,1,n) g[i]=read(),h[i]=qp(i,c);
	rep(i,1,n) 
	{
		rep(j,1,n/i) s[j]=pls(s[j-1],mul(g[i*j],h[j]));
		rep(j,1,n/i)
		{
			if(gcd(i,j)!=1) continue;
			tmp=mul(h[j],s[n/max(i,j)]);
			b[i*j]=pls(b[i*j],tmp);
		}
	}
	rep(i,1,n) ans^=b[i];printf("%d\n",ans);
}

I

修改会改变答案当且仅当\(a[i]+1\)在之前出现过且没被修改过,则可以将\(a[i]++\)使逆序对\(-1\)

对这些情况可以连边\(a[i]\rightarrow a[i]+1\),最终会得到一些链

每一条长度为\(L\)的链会使答案减小\(\lfloor \frac{L}{2}\rfloor\)

#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 200100
#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,to[MAXN],vis[MAXN],c[MAXN],g[MAXN];ll ans;
void mdf(int x){for(;x<=n;x+=x&-x) c[x]++;}
int query(int x,int res=0){for(;x;x-=x&-x) res+=c[x];return res;}
int main()
{
	n=read();rep(i,1,n) {g[i]=read();ans+=query(g[i]);mdf(g[i]);}
	ans=1LL*n*(n-1)/2-ans;int cnt=0,x;
	rep(i,1,n) {if(vis[g[i]+1]) to[g[i]]=g[i]+1;vis[g[i]]=1;}
	Fill(vis,0);
	rep(i,1,n) if(!vis[i])
	{
		cnt=0;x=i;
		while(x) vis[x]=1,cnt++,x=to[x];
		ans-=cnt/2;
	}
	printf("%lld\n",ans);
}

J

要求\(max\{\frac{\sum\limits_{i=a}^b\sum\limits_{j=c}^dW_{i,j}}{(b-a+1)(d-c+1)} \},b-a+1\ge x,d-c+1\ge y\)

\(\frac{\sum\limits_{i=a}^b\sum\limits_{j=c}^dW_{i,j}}{(b-a+1)(d-c+1)}=\sum\limits_{i=a}^b\sum\limits_{j=c}^d\frac{A_i+B_j}{(b-a+1)(d-c+1)}=\frac{\sum\limits_{i=a}^bA_i}{b-a+1}+\frac{\sum\limits_{i=b}^dB_i}{d-c+1}\)

即将问题转化为两个独立的问题,分别求长度不小于某个长度的最大连续子序列平均值

可以二分答案然后用前缀和\(O(n)\)判断

#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 db eps=1e-8;
int n,m,lx,ly,g[MAXN];
db ans,sum[MAXN];
int cheq(db x,int n,int len)
{
	rep(i,1,n) sum[i]=g[i]-x;
	rep(i,2,n) sum[i]+=sum[i-1];
	db res=-inf,mn=inf;rep(i,len,n)
	{
		mn=min(mn,sum[i-len]);
		res=max(res,sum[i]-mn);
	}
	return res>=eps;
}
db work(int n,int len)
{
	db l=inf,r=0,mid;rep(i,1,n) l=min(l,1.0*g[i]),r=max(r,1.0*g[i]);
	while(r-l>eps)
	{
		mid=(l+r)/2;
		if(cheq(mid,n,len)) l=mid;
		else r=mid;
	}
	return l;
}
int main()
{
	n=read(),m=read(),lx=read(),ly=read();
	rep(i,1,n) g[i]=read();ans=work(n,lx);
	rep(i,1,m) g[i]=read();ans+=work(m,ly);
	printf("%.7lf\n",ans);
}
posted @ 2021-07-30 19:17  jack_yyc  阅读(36)  评论(0编辑  收藏  举报