ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

省选测试22

2021-02-17 20:02:08  阅读:190  来源: 互联网

标签:22 省选 tr int rg 测试 nans include now1


A. 送你一道签到题

分析

大概是 \(Min25\) 筛的板子题

很久没有写了,正好复习一下

可以发现题目中给出的式子是一个积性函数

而且是 \(i^k\) 乘上一个系数的形式

所以拿 \(Min25\) 筛筛一个 \(i^k\) 就行了

系数可以用 \(dp\) 预处理

设 \(dp[i][j]\) 为当前填了第 \(i\) 个位置,已经填的幂次为 \(j\) 的方案数,每次必须填

那么幂次为 \(i\) 的系数就是 \(\sum\limits_{i}dp[j][i]C_m^j\)

预处理的时候会有一个自然数幂和的形式,可以拿伯努利数搞一下

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#define rg register
const int maxn=1e6+5,maxk=1e3+5,mod=998244353;
inline int delmod(rg int now1,rg int now2){
	return now1-=now2,now1<0?now1+mod:now1;
}
inline int addmod(rg int now1,rg int now2){
	return now1+=now2,now1>=mod?now1-mod:now1;
}
inline int mulmod(rg long long now1,rg int now2){
	return now1*=now2,now1>=mod?now1%mod:now1;
}
typedef long long ll;
ll n,w[maxn];
int m,k,ny[maxk],b[maxk],c[maxk][maxk];
int ksm(rg int ds,rg ll zs){
	rg int nans=1;
	while(zs){
		if(zs&1LL) nans=mulmod(nans,ds);
		ds=mulmod(ds,ds);
		zs>>=1LL;
	}
	return nans;
}
int getmi(rg ll nn){
	nn++;
	rg int nans=0,tmp=nn%mod;
	for(rg int i=k,now=tmp;i>=0;i--,now=mulmod(now,tmp)){
		nans=addmod(nans,mulmod(c[k+1][i],mulmod(b[i],now)));
	}
	nans=mulmod(nans,ny[k+1]);
	return nans;
}
void pre(){
	ny[1]=1;
	for(rg int i=2;i<=k+1;i++) ny[i]=mulmod(mod-mod/i,ny[mod%i]);
	for(rg int i=0;i<=k+1;i++) c[i][0]=1;
	for(rg int i=1;i<=k+1;i++){
		for(rg int j=1;j<=i;j++){
			c[i][j]=addmod(c[i-1][j],c[i-1][j-1]);
		}
	}
	b[0]=1;
	for(rg int i=1;i<=k+1;i++){
		for(rg int j=0;j<i;j++){
			b[i]=addmod(b[i],mulmod(b[j],c[i+1][j]));
		}
		b[i]=mulmod(b[i],mod-ny[i+1]);
	}
}
bool not_pri[maxn];
int pri[maxn],sp[maxn],sqr,v1[maxn],v2[maxn],tot,g[maxn],mi[maxn];
void xxs(rg int mmax){
	not_pri[0]=not_pri[1]=1;
	for(rg int i=2;i<=mmax;i++){
		if(!not_pri[i]){
			pri[++pri[0]]=i,mi[pri[0]]=ksm(i,k);
			sp[pri[0]]=addmod(sp[pri[0]-1],mi[pri[0]]);
		}
		for(rg int j=1;j<=pri[0] && i*pri[j]<=mmax;j++){
			not_pri[i*pri[j]]=1;
			if(i%pri[j]==0) break;
		}
	}
}
int dp[maxk][maxk],xs[maxk];
int solve(rg ll x,rg int y){
	if(y && x<=pri[y]) return 0;
	rg int now=x<=sqr?v1[x]:v2[n/x];
	rg int ans=mulmod(xs[1],delmod(g[now],sp[y]));
	for(rg int i=y+1;i<=pri[0] && 1LL*pri[i]*pri[i]<=x;i++){
		rg ll np=pri[i];
		for(rg int j=1,tmp=mi[i];np<=x;j++,np*=pri[i],tmp=mulmod(tmp,mi[i])){
			ans=addmod(ans,mulmod(mulmod(xs[j],tmp),addmod(solve(x/np,i),j!=1)));
		}
	}
	return ans;
}
int main(){
	scanf("%lld%d%d",&n,&m,&k);
	pre();
	sqr=sqrt(n);
	xxs(sqr+100);
	rg ll now;
	for(rg ll l=1,r;l<=n;l=r+1){
		r=(n/(n/l));
		now=n/l;
		w[++tot]=now;
		if(now<=sqr) v1[now]=tot;
		else v2[n/now]=tot;
		now%=mod;
		g[tot]=delmod(getmi(now),1);
	}
	for(rg int i=1;1LL*pri[i]*pri[i]<=n;i++){
		for(rg int j=1;j<=tot && 1LL*pri[i]*pri[i]<=w[j];j++){
			now=w[j]/pri[i];
			now=now<=sqr?v1[now]:v2[n/now];
			g[j]=delmod(g[j],mulmod(mi[i],delmod(g[now],sp[i-1])));
		}
	}
	dp[0][0]=1;
	for(rg int i=1;i<=40;i++){
		for(rg int j=0;j<=40;j++){
			for(rg int o=j+1;o<=40;o++){
				dp[i][o]=addmod(dp[i][o],mulmod(dp[i-1][j],o-j+1));
			}
		}
	}
	for(rg int i=1;i<=40;i++){
		for(rg int j=1,tmp=m;j<=40;j++){
			xs[i]=addmod(xs[i],mulmod(dp[j][i],tmp));
			tmp=mulmod(tmp,mulmod(ny[j+1],m-j));
		}
	}
	printf("%d\n",addmod(solve(n,0),1));
	return 0;
}

B. 神犇

分析

看到异或和可以想到差分和 \(01trie\)

记录一下 \(0,1,2\) 出现次数的前缀和,分别设为 \(sum0,sum1,sum2\)

对于一个 \(r\),查询最大的 \(sumxor[r]\ xor\ sumxor[l]\)

并且满足 \(sum0[r]-sum0[l] \neq sum1[r]-sum1[l] \neq sum2[r]-sum2[l]\)

后面的三个式子移项之后就只和 \(l\) 或者 \(r\)有关

也就是找到一个 \(l\)

使得 \(sum1[l]-sum0[l] \ne sum1[r]-sum0[r]\)

\(sum2[l]-sum1[l] \neq sum2[r]-sum1[r]\)

\(sum0[l]-sum2[l] \neq sum0[r]-sum2[r]\)

把这三个差分别设成 \(val1,val2,val3\)

就是要 \(val1[l] \neq val1[r],val2[l] \neq val2[r],val3[l] \neq val3[r]\)

而且 \(sumxor[r]\ xor\ sumxor[l]\) 最大

记录 \(trie\) 树上每一个节点出现的次数

容斥一下

那么答案就是总的- \(a\)相等的 - \(b\) 相等的- \(c\) 相等+\(ab\) 都相等的+\(ac\) 都相等的+\(bc\)都相等的-\(abc\)都相等的

然后会发现 \(ab\) 相等就等价于 \(abc\) 相等 \(,\) 同理

也就是后面的 \(4\) 个可以合成一个

最终的答案就是 \(all-a-b-c+2abc\)

对于这 \(5\) 种 \(trie\) 树的每一个值都开一棵 \(trie\) 树

最后空间大概是 \(400MiB\)

代码

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<set>
#include<vector>
#include<map>
#define rg register
inline int read(){
	rg int x=0,fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*fh;
}
typedef unsigned long long ull;
const int maxn=3e5+5;
std::map<ull,int> mp1;
std::map<int,int> mp2[3];
int n,a[maxn],op,latans,p[maxn],totrt;
int tr[maxn*120][2],cnt,sum0[maxn],sum1[maxn],sum2[maxn],sumxor[maxn],siz[maxn*120];
void ad(rg int da,rg int val){
	for(rg int i=31;i>=1;i--){
		rg int p=(val>>(i-1))&1;
		if(!tr[da][p]) tr[da][p]=++cnt;
		da=tr[da][p];
		siz[da]++;
	}
}
int cx(rg int rt1,rg int rt2,rg int rt3,rg int rt4,rg int rt5,rg int val){
	rg int nans=0;
	for(rg int i=31;i>=1;i--){
		rg int p=(val>>(i-1))&1;
		rg int tmp=siz[tr[rt1][p^1]]-siz[tr[rt2][p^1]]-siz[tr[rt3][p^1]]-siz[tr[rt4][p^1]]+2*siz[tr[rt5][p^1]];
		if(tmp){
			rt1=tr[rt1][p^1],rt2=tr[rt2][p^1],rt3=tr[rt3][p^1],rt4=tr[rt4][p^1],rt5=tr[rt5][p^1];
			nans+=(1<<(i-1));
		} else {
			rt1=tr[rt1][p],rt2=tr[rt2][p],rt3=tr[rt3][p],rt4=tr[rt4][p],rt5=tr[rt5][p];
		}
	}
	return nans;
}
int main(){
	n=read(),op=read();
	for(rg int i=1;i<=n;i++) p[i]=read();
	for(rg int i=1;i<=n;i++) a[i]=read();
	rg int op1,op2,op3;
	for(rg int i=1;i<=n;i++){
		if(op) p[i]=(latans^p[i])%3;
		if(op) a[i]=latans^a[i];
		sum0[i]=sum0[i-1]+(p[i]==0);
		sum1[i]=sum1[i-1]+(p[i]==1);
		sum2[i]=sum2[i-1]+(p[i]==2);
		sumxor[i]=sumxor[i-1]^a[i];
		op1=sum0[i-1]-sum1[i-1],op2=sum1[i-1]-sum2[i-1],op3=sum2[i-1]-sum0[i-1];
		if(!totrt) totrt=++cnt;
		ad(totrt,sumxor[i-1]);
		if(!mp2[0][op1]) mp2[0][op1]=++cnt;
		ad(mp2[0][op1],sumxor[i-1]);
		if(!mp2[1][op2]) mp2[1][op2]=++cnt;
		ad(mp2[1][op2],sumxor[i-1]);
		if(!mp2[2][op3]) mp2[2][op3]=++cnt;
		ad(mp2[2][op3],sumxor[i-1]);
		if(!mp1[(unsigned long long)op1*n*n+op2*n+op3]) mp1[(unsigned long long)op1*n*n+op2*n+op3]=++cnt;
		ad(mp1[(unsigned long long)op1*n*n+op2*n+op3],sumxor[i-1]);
		op1=sum0[i]-sum1[i],op2=sum1[i]-sum2[i],op3=sum2[i]-sum0[i];
		latans=cx(totrt,mp2[0][op1],mp2[1][op2],mp2[2][op3],mp1[(unsigned long long)op1*n*n+op2*n+op3],sumxor[i]);
		printf("%d ",latans);
	}
	printf("\n");
	return 0;
}

C. 开挂

分析

枚举含有 \(1\) 的矩形的大小

为了避免重复,要满足矩形的四个边界上都有 \(1\)

最优的方案肯定是选左下右上或者左上右下

把四个边界和不包含在哪种方案中状压一下即可

代码

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
#define rg register
inline int read(){
	rg int x=0,fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*fh;
}
const int maxn=65,maxm=75,mod=998244353;
inline int addmod(rg int now1,rg int now2){
	return now1+=now2,now1>=mod?now1-mod:now1;
}
inline int delmod(rg int now1,rg int now2){
	return now1-=now2,now1<0?now1+mod:now1;
}
inline int mulmod(rg long long now1,rg int now2){
	return now1*=now2,now1>=mod?now1%mod:now1;
}
int n,m,ans=1,x,y,f[2][maxm];
int getzt(rg int mx,rg int my,rg int nx,rg int ny){
	rg int nzt=0;
	if(mx==1) nzt|=1;
	if(mx==nx) nzt|=2;
	if(my==1) nzt|=4;
	if(my==ny) nzt|=8;
	if(!(mx<=x && my<=y) && !(nx-mx+1<=x && ny-my+1<=y)) nzt|=16;
	if(!(nx-mx+1<=x && my<=y) && !(mx<=x && ny-my+1<=y)) nzt|=32;
	return nzt;
}
int solve(rg int nx,rg int ny){
	rg int now=1;
	memset(f,0,sizeof(f));
	f[1][getzt(1,1,nx,ny)]=f[1][0]=1;
	for(rg int i=1;i<=nx;i++){
		for(rg int j=1;j<=ny;j++){
			if(i==1 && j==1) continue;
			now^=1;
			memset(f[now],0,sizeof(f[now]));
			rg int tmp=getzt(i,j,nx,ny);
			for(rg int k=0;k<=63;k++){
				f[now][k]=addmod(f[now][k],f[now^1][k]);
				f[now][k|tmp]=addmod(f[now][k|tmp],f[now^1][k]);
			}
		}
	}
	rg int nans=addmod(addmod(f[now][31],f[now][47]),f[now][15]);
	return nans;
}
int main(){
	n=read(),m=read(),x=read(),y=read();
	for(rg int i=1;i<=n;i++){
		for(rg int j=1;j<=m;j++){
			ans=addmod(ans,mulmod(solve(i,j),mulmod(n-i+1,m-j+1)));
		}
	}
	printf("%d\n",ans);
	return 0;
}

标签:22,省选,tr,int,rg,测试,nans,include,now1
来源: https://www.cnblogs.com/liuchanglc/p/14409540.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有