Ynoi合集

level 0:

P6328 我是仙人掌

bitset简单题,用bitset+bfs维护一下与1-n中每个节点不超过x的节点有哪些,求答案时或起来就好了。
代码:

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define int long long
struct IO
{
	static const int Size=(1<<21);
	char buf[Size],*p1,*p2;
	int st[105],Top;
	~IO(){clear();}
	il void clear(){fwrite(buf,1,Top,stdout);Top=0;}
	il char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,Size,stdin),p1==p2)?EOF:*p1++;}
	il void pc(const char c){Top==Size&&(clear(),0);buf[Top++]=c;}
	il IO& operator >>(char& c){while(c=gc(),c==' ' || c=='\n' || c=='\r');return *this;}
	template<typename T>il IO& operator >>(T& x)
	{
		x=0;bool f=0;char c=gc();
		while(!isdigit(c)){if(c=='-') f=1;c=gc();}
		while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
		f?x=-x:0;
		return *this;
	}
	il IO& operator >>(string& s)
	{
		s="";char c=gc();
		while(c==' ' || c=='\n' || c=='\r') c=gc();
		while(c!=' ' && c!='\n' && c!='\r' && c!=EOF) s+=c,c=gc();
		return *this;
	}
	il IO& operator <<(const char c){pc(c);return *this;}
	template<typename T> il IO& operator <<(T x)
	{
		if(x<0) pc('-'),x=-x;
		do st[++st[0]]=x%10,x/=10;while(x);
		while(st[0]) pc(st[st[0]--]+'0');
		return *this;
	}
	il IO& operator <<(const string s){for(auto c:s) pc(c);return *this;}
	il IO& operator <<(const char* c){for(int i=0;c[i];i++) pc(c[i]);return *this;}
} fin,fout;
const int N=1010;
int maxd[N],d[N];
vector<int> g[N];
bitset<N> st[N][N];
queue<int> Q;
signed main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	int n,m,q;fin>>n>>m>>q;
	for(int i=1;i<=m;i++)
	{
		int u,v;fin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++) d[j]=0;
		Q.push(i);
		while(!Q.empty())
		{
			int u=Q.front();Q.pop();
			maxd[i]=max(maxd[i],d[u]);
			st[i][d[u]][u]=1;
			for(int v:g[u])
			{
				if(!d[v] && v!=i) d[v]=d[u]+1,Q.push(v);
			}
		}
		for(int j=1;j<=maxd[i];j++) st[i][j]|=st[i][j-1];
	}
	while(q--)
	{
		int k;fin>>k;
		bitset<N> tmp=0;
		for(int i=1;i<=k;i++)
		{
			int x,y;fin>>x>>y;
			tmp|=st[x][min(maxd[x],y)];
		}
		fout<<tmp.count()<<"\n";
	}
	return 0;
}

P6327 区间加区间sin和

三角函数简单题。由和角公式\(\sin(\alpha+\beta)=\sin(\alpha)\cos(a\beta+\cos(\alpha)\sin(\beta)\)\(\cos(\alpha+\beta)=\cos(\alpha)\cos(\beta)-\sin(\alpha)\sin(\beta)\)放进push_down里跑一下就好了。
代码:

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define int long long
#define lid id<<1
#define rid id<<1|1
struct IO
{
	static const int Size=(1<<21);
	char buf[Size],*p1,*p2;
	int st[105],Top;
	~IO(){clear();}
	il void clear(){fwrite(buf,1,Top,stdout);Top=0;}
	il char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,Size,stdin),p1==p2)?EOF:*p1++;}
	il void pc(const char c){Top==Size&&(clear(),0);buf[Top++]=c;}
	il IO& operator >>(char& c){while(c=gc(),c==' ' || c=='\n' || c=='\r');return *this;}
	template<typename T>il IO& operator >>(T& x)
	{
		x=0;bool f=0;char c=gc();
		while(!isdigit(c)){if(c=='-') f=1;c=gc();}
		while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
		f?x=-x:0;
		return *this;
	}
	il IO& operator >>(string& s)
	{
		s="";char c=gc();
		while(c==' ' || c=='\n' || c=='\r') c=gc();
		while(c!=' ' && c!='\n' && c!='\r' && c!=EOF) s+=c,c=gc();
		return *this;
	}
	il IO& operator <<(const char c){pc(c);return *this;}
	template<typename T> il IO& operator <<(T x)
	{
		if(x<0) pc('-'),x=-x;
		do st[++st[0]]=x%10,x/=10;while(x);
		while(st[0]) pc(st[st[0]--]+'0');
		return *this;
	}
	il IO& operator <<(const string s){for(auto c:s) pc(c);return *this;}
	il IO& operator <<(const char* c){for(int i=0;c[i];i++) pc(c[i]);return *this;}
} fin,fout;
const int N=200010;
int a[N];
struct TreeNode
{
	double scos,ssin;
	int lazy;
} t[N<<2];
il void push_up(int id)
{
	t[id].ssin=t[lid].ssin+t[rid].ssin;
	t[id].scos=t[lid].scos+t[rid].scos;
}
il void lazy_add(int id,int k)
{
	t[id].lazy+=k;
	double s1=t[id].ssin,s2=t[id].scos;
	t[id].ssin=s1*cos(k)+s2*sin(k);
	t[id].scos=s2*cos(k)-s1*sin(k);
}
il void push_down(int id)
{
	if(t[id].lazy)
	{
		lazy_add(lid,t[id].lazy);
		lazy_add(rid,t[id].lazy);
		t[id].lazy=0;
	}
}
il void build(int id,int l,int r)
{
	if(l==r)
	{
		t[id].ssin=sin(a[l]);
		t[id].scos=cos(a[l]);
		return;
	}
	int mid=(l+r)>>1;
	build(lid,l,mid);
	build(rid,mid+1,r);
	push_up(id);
}
il void add(int id,int l,int r,int L,int R,int k)
{
	if(L<=l && r<=R)
	{
		lazy_add(id,k);
		return;
	}
	push_down(id);
	int mid=(l+r)>>1;
	if(L<=mid) add(lid,l,mid,L,R,k);
	if(R>mid) add(rid,mid+1,r,L,R,k);
	push_up(id);
}
il double query_ssin(int id,int l,int r,int L,int R)
{
	if(L<=l && r<=R) return t[id].ssin;
	push_down(id);
	int mid=(l+r)>>1;
	double ret=0;
	if(L<=mid) ret+=query_ssin(lid,l,mid,L,R);
	if(R>mid) ret+=query_ssin(rid,mid+1,r,L,R);
	return ret;
}
signed main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	int n;fin>>n;
	for(int i=1;i<=n;i++) fin>>a[i];
	build(1,1,n);
	int q;fin>>q;
	while(q--)
	{
		int op,l,r;fin>>op>>l>>r;
		if(op==1)
		{
			int k;fin>>k;
			add(1,1,n,l,r,k);
		}
		else cout<<fixed<<setprecision(1)<<query_ssin(1,1,n,l,r)<<"\n";
	}
	return 0;
}

level 1:

P5354 由乃的OJ

首先二进制考虑按位贪心,用树剖+线段树记录树链u到v的第i个二进制位放进去0/1后出来的值,可以做到\(O(mlog^2nlogV)\),考虑继续优化,发现所有位都可以一起转移,故可以做到\(O(mlog^2n+mlogV)\),可以通过。
代码:

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ull unsigned long long
#define lid id<<1
#define rid id<<1|1
struct IO
{
	static const int Size=(1<<21);
	char buf[Size],*p1,*p2;
	int st[105],Top;
	~IO(){clear();}
	il void clear(){fwrite(buf,1,Top,stdout);Top=0;}
	il char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,Size,stdin),p1==p2)?EOF:*p1++;}
	il void pc(const char c){Top==Size&&(clear(),0);buf[Top++]=c;}
	il IO& operator >>(char& c){while(c=gc(),c==' ' || c=='\n' || c=='\r');return *this;}
	template<typename T>il IO& operator >>(T& x)
	{
		x=0;bool f=0;char c=gc();
		while(!isdigit(c)){if(c=='-') f=1;c=gc();}
		while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
		f?x=-x:0;
		return *this;
	}
	il IO& operator >>(string& s)
	{
		s="";char c=gc();
		while(c==' ' || c=='\n' || c=='\r') c=gc();
		while(c!=' ' && c!='\n' && c!='\r' && c!=EOF) s+=c,c=gc();
		return *this;
	}
	il IO& operator <<(const char c){pc(c);return *this;}
	template<typename T> il IO& operator <<(T x)
	{
		if(x<0) pc('-'),x=-x;
		do st[++st[0]]=x%10,x/=10;while(x);
		while(st[0]) pc(st[st[0]--]+'0');
		return *this;
	}
	il IO& operator <<(const string s){for(auto c:s) pc(c);return *this;}
	il IO& operator <<(const char* c){for(int i=0;c[i];i++) pc(c[i]);return *this;}
} fin,fout;
const int N=100010;
const ull V=-1;
int siz[N],son[N],d[N],f[N],top[N],dfn[N],tot,val[N],n,m,k;
vector<int> g[N];
struct node
{
	int op;
	ull w;
} a[N];
struct TreeNode
{
	ull w0,w1,fw0,fw1;
} t[N<<2];
il void get_son(int u,int fa)
{
	d[u]=d[fa]+1;f[u]=fa;siz[u]=1;
	for(int v:g[u])
	{
		if(v==fa) continue;
		get_son(v,u);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]]) son[u]=v;
	}
}
il void get_top(int u,int t)
{
	top[u]=t;val[dfn[u]=++tot]=u;
	if(son[u]) get_top(son[u],t);
	for(int v:g[u])
	{
		if(v==f[u] || v==son[u]) continue;
		get_top(v,v);
	}
}
il void push_up(int id)
{
	t[id].w0=(t[lid].w0&t[rid].w1)|((t[lid].w0^V)&t[rid].w0);
	t[id].w1=(t[lid].w1&t[rid].w1)|((t[lid].w1^V)&t[rid].w0);
	t[id].fw0=(t[rid].fw0&t[lid].fw1)|((t[rid].fw0^V)&t[lid].fw0);
	t[id].fw1=(t[rid].fw1&t[lid].fw1)|((t[rid].fw1^V)&t[lid].fw0);
}
il void build(int id,int l,int r)
{
	if(l==r)
	{
		if(a[val[l]].op==1) t[id].w0=t[id].fw0=0,t[id].w1=t[id].fw1=a[val[l]].w;
		else if(a[val[l]].op==2) t[id].w0=t[id].fw0=a[val[l]].w,t[id].w1=t[id].fw1=V;
		else t[id].w0=t[id].fw0=a[val[l]].w,t[id].w1=t[id].fw1=V^a[val[l]].w;
		return;
	}
	int mid=(l+r)>>1;
	build(lid,l,mid);
	build(rid,mid+1,r);
	push_up(id);
}
il void change(int id,int l,int r,int x,node w)
{
	if(l==r)
	{
		a[val[l]]=w;
		if(a[val[l]].op==1) t[id].w0=t[id].fw0=0,t[id].w1=t[id].fw1=a[val[l]].w;
		else if(a[val[l]].op==2) t[id].w0=t[id].fw0=a[val[l]].w,t[id].w1=t[id].fw1=V;
		else t[id].w0=t[id].fw0=a[val[l]].w,t[id].w1=t[id].fw1=V^a[val[l]].w;
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid) change(lid,l,mid,x,w);
	else change(rid,mid+1,r,x,w);
	push_up(id);
}
il pair<ull,ull> query_zheng(int id,int l,int r,int L,int R)
{
	if(L<=l && r<=R) return {t[id].w0,t[id].w1};
	int mid=(l+r)>>1;
	if(R<=mid) return query_zheng(lid,l,mid,L,R);
	else if(L>mid) return query_zheng(rid,mid+1,r,L,R);
	else
	{
		auto tmp1=query_zheng(lid,l,mid,L,R),tmp2=query_zheng(rid,mid+1,r,L,R);
		ull ret1=0,ret2=0;
		ret1=(tmp1.first&tmp2.second)|((tmp1.first^V)&tmp2.first);
		ret2=(tmp1.second&tmp2.second)|((tmp1.second^V)&tmp2.first);
		return {ret1,ret2};
	}
}
il pair<ull,ull> query_fan(int id,int l,int r,int L,int R)
{
	if(L<=l && r<=R) return {t[id].fw0,t[id].fw1};
	int mid=(l+r)>>1;
	if(R<=mid) return query_fan(lid,l,mid,L,R);
	else if(L>mid) return query_fan(rid,mid+1,r,L,R);
	else
	{
		auto tmp1=query_fan(lid,l,mid,L,R),tmp2=query_fan(rid,mid+1,r,L,R);
		ull ret1=0,ret2=0;
		ret1=(tmp2.first&tmp1.second)|((tmp2.first^V)&tmp1.first);
		ret2=(tmp2.second&tmp1.second)|((tmp2.second^V)&tmp1.first);
		return {ret1,ret2};
	}
}
il pair<ull,ull> link_query(int u,int v)
{
	pair<ull,ull> ret1={0,V},ret2={0,V};
	int op=0;
	while(top[u]!=top[v])
	{
		if(d[top[u]]<d[top[v]]) swap(u,v),op^=1;
//		fout<<u<<' '<<v<<" "<<op<<"\n";
		if(op==0)
		{
			auto tmp=query_fan(1,1,n,dfn[top[u]],dfn[u]);
			ull tmp1,tmp2;
			tmp1=(ret1.first&tmp.second)|((ret1.first^V)&tmp.first);
			tmp2=(ret1.second&tmp.second)|((ret1.second^V)&tmp.first);
			ret1={tmp1,tmp2};
		}
		else
		{
			auto tmp=query_zheng(1,1,n,dfn[top[u]],dfn[u]);
			ull tmp1,tmp2;
			tmp1=(tmp.first&ret2.second)|((tmp.first^V)&ret2.first);
			tmp2=(tmp.second&ret2.second)|((tmp.second^V)&ret2.first);
			ret2={tmp1,tmp2};
		}
		u=f[top[u]];
	}
	if(d[u]<d[v]) swap(u,v),op^=1;
	if(op==0)
	{
		auto tmp=query_fan(1,1,n,dfn[v],dfn[u]);
		ull tmp1,tmp2;
		tmp1=(ret1.first&tmp.second)|((ret1.first^V)&tmp.first);
		tmp2=(ret1.second&tmp.second)|((ret1.second^V)&tmp.first);
		ret1={tmp1,tmp2};
	}
	else
	{
		auto tmp=query_zheng(1,1,n,dfn[v],dfn[u]);
		ull tmp1,tmp2;
		tmp1=(tmp.first&ret2.second)|((tmp.first^V)&ret2.first);
		tmp2=(tmp.second&ret2.second)|((tmp.second^V)&ret2.first);
		ret2={tmp1,tmp2};
	}
	ull tmp1,tmp2;
	tmp1=(ret1.first&ret2.second)|((ret1.first^V)&ret2.first);
	tmp2=(ret1.second&ret2.second)|((ret1.second^V)&ret2.first);
	return {tmp1,tmp2};
}
signed main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	fin>>n>>m>>k;
	for(int i=1;i<=n;i++) fin>>a[i].op>>a[i].w;
	for(int i=1;i<n;i++)
	{
		int u,v;fin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	get_son(1,0);get_top(1,1);
	build(1,1,n);
	while(m--)
	{
		int op,x,y;ull z;fin>>op>>x>>y>>z;
		if(op==1)
		{
			ull w0,w1;
			tie(w0,w1)=link_query(x,y);
//			fout<<w0<<" "<<w1<<'\n';
			int fl=1;ull ans=0;
			for(int i=k-1;i>=0;i--)
			{
				if(fl)
				{
					if(z>>i&1)
					{
						if(w0>>i&1) ans|=(1ull<<i),fl=0;
						else if(w1>>i&1) ans|=(1ull<<i);
						else fl=0;
					}
					else if(w0>>i&1) ans|=(1ull<<i);
				}
				else if((w0>>i&1) || (w1>>i&1)) ans|=(1ull<<i);
			}
			fout<<ans<<"\n";
		}
		else change(1,1,n,dfn[x],{y,z});
	}
	return 0;
}

P5607 无力回天

\(m=1e6\)容易误导人想\(O(mlogm)\)做法,然而这并不好做。正解为根号分治,设定阈值\(B\),离线下来后出现次数大于\(B\)则用bitset优化由于数字个数不会超过\(\frac{m}{B}\)个,所以时间复杂度不会超过\(O(\frac{m^2}{wB})\),另一部分可以使用并等于两个部分的和减去两个部分的交,交则可以用哈希表统计,由于这些数字的出现次数不会超过\(B\),所以每一次加入新增的数对不会超过\(B\),这部分时间复杂度不会超过\(O(mB)\)\(B\)\(\sqrt{\frac{m}{w}}\),时有最小值\(O(m\sqrt{\frac{m}{w}})\),大约是\(1.25*1e8\)的复杂度,空间有点大,可能得用分块bitset。
代码:

#include<bits/stdc++.h>
using namespace std;
#define il inline
bool St;
struct IO
{
	static const int Size=(1<<21);
	char buf[Size],*p1,*p2;
	int st[105],Top;
	~IO(){clear();}
	il void clear(){fwrite(buf,1,Top,stdout);Top=0;}
	il char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,Size,stdin),p1==p2)?EOF:*p1++;}
	il void pc(const char c){Top==Size&&(clear(),0);buf[Top++]=c;}
	il IO& operator >>(char& c){while(c=gc(),c==' ' || c=='\n' || c=='\r');return *this;}
	template<typename T>il IO& operator >>(T& x)
	{
		x=0;bool f=0;char c=gc();
		while(!isdigit(c)){if(c=='-') f=1;c=gc();}
		while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
		f?x=-x:0;
		return *this;
	}
	il IO& operator >>(string& s)
	{
		s="";char c=gc();
		while(c==' ' || c=='\n' || c=='\r') c=gc();
		while(c!=' ' && c!='\n' && c!='\r' && c!=EOF) s+=c,c=gc();
		return *this;
	}
	il IO& operator <<(const char c){pc(c);return *this;}
	template<typename T> il IO& operator <<(T x)
	{
		if(x<0) pc('-'),x=-x;
		do st[++st[0]]=x%10,x/=10;while(x);
		while(st[0]) pc(st[st[0]--]+'0');
		return *this;
	}
	il IO& operator <<(const string s){for(auto c:s) pc(c);return *this;}
	il IO& operator <<(const char* c){for(int i=0;c[i];i++) pc(c[i]);return *this;}
} fin,fout;
const int N=1000010,B=150;
int cnt[N],vis[N],lsh[N],ans[N];
struct Hash_map
{
	static const int Mod=1e6+3;
	int h[Mod],tot;
	struct node
	{
		int nxt;
		pair<int,int> key;
	} e[N];
	int MyHash(pair<int,int> x)
	{
		return (1ll*x.first*998244353+x.second)%Mod;
	}
	void ins(pair<int,int> x)
	{
		int id=MyHash(x);
		for(int i=h[id];i;i=e[i].nxt)
		{
			if(e[i].key==x) return;
		}
		tot++;
		e[tot].nxt=h[id],e[tot].key=x;
		h[id]=tot;
	}
	int find(pair<int,int> x)
	{
		int id=MyHash(x);
		for(int i=h[id];i;i=e[i].nxt)
		{
			if(e[i].key==x) return 1;
		}
		return 0;
	}
} mp;
struct Hash_map2
{
	static const int Mod=1e6+3;
	int h[Mod],tot;
	struct node
	{
		int nxt,val;
		pair<int,int> key;
	} e[N];
	int MyHash(pair<int,int> x)
	{
		return (1ll*x.first*998244353+x.second)%Mod;
	}
	void add(pair<int,int> x,int y)
	{
		int id=MyHash(x);
		for(int i=h[id];i;i=e[i].nxt)
		{
			if(e[i].key==x)
			{
				e[i].val+=y;
				return;
			}
		}
		tot++;
		e[tot].nxt=h[id],e[tot].key=x;e[tot].val=y;
		h[id]=tot;
	}
	int query(pair<int,int> x)
	{
		int id=MyHash(x);
		for(int i=h[id];i;i=e[i].nxt)
		{
			if(e[i].key==x) return e[i].val;
		}
		return 0;
	}
} val;
bitset<N/B/2+10> b[N];
vector<int> idx[N];
struct node
{
	int op,x,y;
} q[N];
bool Ed;
signed main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
//	cerr<<(&St-&Ed)/1024.0/1024.0<<"\n";
	int m;fin>>m;
	for(int i=1;i<=m;i++)
	{
		fin>>q[i].op>>q[i].x>>q[i].y;
		if(q[i].op==1) vis[q[i].y]++;
		else
		{
			if(q[i].x>q[i].y) swap(q[i].x,q[i].y);
			mp.ins({q[i].x,q[i].y});
		}
	}
	int tmp=0;
	for(int i=1;i<=m;i++) if(vis[i]>B) lsh[i]=tmp++;
	for(int i=1;i<=m;i++)
	{
		if(q[i].op==1)
		{
			if(vis[q[i].y]<=B)
			{
				idx[q[i].y].emplace_back(q[i].x);
				for(int j:idx[q[i].y])
				{
					if(j<q[i].x)
					{
						if(mp.find({j,q[i].x})) val.add({j,q[i].x},1);
					}
					else if(mp.find({q[i].x,j})) val.add({q[i].x,j},1);
				}
				cnt[q[i].x]++;
			}
			else if(lsh[q[i].y]<=N/B/2) b[q[i].x][lsh[q[i].y]]=1;
		}
		else
		{
			ans[i]=(cnt[q[i].x]+cnt[q[i].y]);
			ans[i]-=val.query({q[i].x,q[i].y});
			ans[i]+=(b[q[i].x]|b[q[i].y]).count();
		}
	}
	for(int i=1;i<=m;i++) b[i]=0;
	for(int i=1;i<=m;i++)
	{
		if(q[i].op==1)
		{
			if(vis[q[i].y]>B && lsh[q[i].y]>N/B/2) b[q[i].x][lsh[q[i].y]-N/B/2]=1;
		}
		else fout<<ans[i]+(b[q[i].x]|b[q[i].y]).count()<<"\n";
	}
	return 0;
}

P6108 rprsvq

组合数学好题。
首先拆式子。

\[\begin{aligned} \frac{1}{n}\sum_{i=1}^{n}(a_i-\bar{a})^2&=\frac{1}{n}\sum_{i=1}^{n}(a_i^2+\bar{a}^2-2\times a_i\times\bar{a})\\ &=(\frac{1}{n}\sum_{i=1}^na_i^2)+\bar{a}^2-(\frac{2}{n}\bar{a}\sum_{i=1}^na_i)\\ &=(\frac{1}{n}\sum_{i=1}^na_i^2)+(\frac{1}{n^2}(\sum_{i=1}^na_i)^2)-(\frac{2}{n^2}(\sum_{i=1}^na_i)^2)\\ &=(\frac{1}{n}\sum_{i=1}^na_i^2)-(\frac{1}{n^2}(\sum_{i=1}^na_i)^2) \end{aligned} \]

然后拆系数
\(s_1=\sum_{i=1}^na_i,s_2=\sum_{i=1}^na_i^2\)
首先是\(s_2\)\(ans\)中的系数,
\(s_2\)在前项中系数为\(\sum_{i=0}^{r-l} C_{r-l}^{i}\times \frac{1}{i+1}\)其中第\(i\)项表示\(a_i^2\)在长为\(i+1\)的序列里的贡献。在后项中的系数为\(-\sum_{i=0}^{r-l} C_{r-l}^{i}\times \frac{1}{(i+1)^2}\),计算方式同上。
\(s_1^2-s_2\)的系数只在后项中有,为\(-\sum_{i=0}^{r-l-1} C_{r-l-1}^{i}\times \frac{1}{(i+2)^2}\)其中第\(i\)项表示现在已经钦定两个数必选,剩余数一共选\(i\)个,总共选的区间长度为\(i+2\)的贡献。
其中\(s_1\)可以用线段树轻松维护,\((s_2+k)^2=s_2^2+2s_2k+k^2\),把这个式子写到push_down里就可以求出动态维护\(s_2\)
然后我们需要快速处理出三个系数的式子。
第一个:\(h(n)=\sum_{i=0}^{n} C_{n}^{i}\times \frac{1}{i+1}\)

\[\begin{aligned} h(n)&=\sum_{i=0}^{n} C_{n}^{i}\times \frac{1}{i+1}\\ &=\sum_{i=0}^{n} \frac{n!}{(i+1)i!(n-i)!}\\ &=\frac{1}{n+1}\sum_{i=0}^{n} \frac{(n+1)!}{(i+1)!(n-i)!}\\ &=\frac{1}{n+1}\sum_{i=0}^{n} C_{n+1}^{i+1}\\ &=\frac{1}{n+1}\sum_{i=1}^{n+1} C_{n+1}^{i}\\ &=\frac{1}{n+1}(2^{n+1}-1) \end{aligned} \]

第二个:\(\sum_{i=0}^{n} C_{n}^{i}\times \frac{1}{(i+1)^2}\)

\[\begin{aligned} \sum_{i=0}^{n} C_{n}^{i}\times \frac{1}{(i+1)^2}&=\frac{1}{n+1}\sum_{i=0}^{n}C_{n+1}^{i+1}\cdot \frac{1}{i+1}\\ &=\frac{1}{n+1}\sum_{i=1}^{n+1}C_{n+1}^{i}\cdot \frac{1}{i} \end{aligned} \]

\(f(n)=\sum_{i=1}^{n+1}C_{n+1}^{i}\cdot \frac{1}{i}\)
则有

\[\begin{aligned} f(n)&=\sum_{i=1}^{n+1}C_{n+1}^{i}\cdot \frac{1}{i}\\ &=\sum_{i=1}^{n+1}C_{n}^{i}\cdot \frac{1}{i}+\sum_{i=1}^{n+1}C_{n}^{i-1}\cdot \frac{1}{i}\\ &=\sum_{i=1}^{n}C_{n}^{i}\cdot \frac{1}{i}+\sum_{i=0}^{n}C_{n}^{i-1}\cdot \frac{1}{i+1}\\ &=f(n-1)+h(n) \end{aligned} \]

\(O(n)\)递推求出。
所以可以\(O(n)\)求出\(1-n\)的第二种系数。
第三个:\(g(n)=\sum_{i=0}^{n} C_{n}^{i}\times \frac{1}{(i+2)^2}\)

\[\begin{aligned} g(n)&=\sum_{i=0}^{n} C_{n}^{i}\times \frac{1}{(i+2)^2}\\ &=\sum_{i=0}^{n} \frac{n!}{i!(n-i)!(i+2)^2}\\ &=\frac{1}{(n+1)(n+2)}\sum_{i=0}^{n} \frac{(n+2)!}{(i+2)!(n-i)!}\times \frac{i+1}{i+2}\\ &=\frac{1}{(n+1)(n+2)}\sum_{i=2}^{n+2} C_{n+2}^{i}\times \frac{i}{i-1}\\ &=\frac{1}{(n+1)(n+2)}(\sum_{i=2}^{n+2} C_{n+2}^{i}-\sum_{i=2}^{n+2} C_{n+2}^{i}\times \frac{1}{i})\\ &=\frac{1}{(n+1)(n+2)}(\sum_{i=0}^{n+2} C_{n+2}^{i}-1-(n+2)-\sum_{i=1}^{n+2} C_{n+2}^{i}\times \frac{1}{i}+(n+2))\\ &=\frac{1}{(n+1)(n+2)}(2^{n+2}-1-f(n+1)) \end{aligned} \]

所以可以\(O(n)\)求出\(g(1)-g(n)\)。这个题就做完了。
代码:

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define lid id<<1
#define rid id<<1|1
struct IO
{
	static const int Size=(1<<21);
	char buf[Size],*p1,*p2;
	int st[105],Top;
	~IO(){clear();}
	il void clear(){fwrite(buf,1,Top,stdout);Top=0;}
	il char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,Size,stdin),p1==p2)?EOF:*p1++;}
	il void pc(const char c){Top==Size&&(clear(),0);buf[Top++]=c;}
	il IO& operator >>(char& c){while(c=gc(),c==' ' || c=='\n' || c=='\r');return *this;}
	template<typename T>il IO& operator >>(T& x)
	{
		x=0;bool f=0;char c=gc();
		while(!isdigit(c)){if(c=='-') f=1;c=gc();}
		while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
		f?x=-x:0;
		return *this;
	}
	il IO& operator >>(string& s)
	{
		s="";char c=gc();
		while(c==' ' || c=='\n' || c=='\r') c=gc();
		while(c!=' ' && c!='\n' && c!='\r' && c!=EOF) s+=c,c=gc();
		return *this;
	}
	il IO& operator <<(const char c){pc(c);return *this;}
	template<typename T> il IO& operator <<(T x)
	{
		if(x<0) pc('-'),x=-x;
		do st[++st[0]]=x%10,x/=10;while(x);
		while(st[0]) pc(st[st[0]--]+'0');
		return *this;
	}
	il IO& operator <<(const string s){for(auto c:s) pc(c);return *this;}
	il IO& operator <<(const char* c){for(int i=0;c[i];i++) pc(c[i]);return *this;}
} fin,fout;
const int N=5000010,mod=998244353;
int jc[N],fjc[N],inv[N],pow2[N],f[N],g[N],limit=1,l;
struct node
{
	int s,s2,lazy;
} t[N<<2];
il void upd(int& x,int y){x=(x+y>=mod)?x+y-mod:x+y;}
il void push_up(int id)
{
	t[id].s=(t[lid].s+t[rid].s)%mod;
	t[id].s2=(t[lid].s2+t[rid].s2)%mod;
}
il void lazy_add(int id,int k,int l,int r)
{
	upd(t[id].lazy,k);
	t[id].s2=(t[id].s2+(2ll*t[id].s*k%mod+1ll*k*k%mod*(r-l+1)%mod))%mod;
	t[id].s=(t[id].s+1ll*k*(r-l+1))%mod;
}
il void push_down(int id,int l,int r)
{
	if(t[id].lazy)
	{
		int mid=(l+r)>>1;
		lazy_add(lid,t[id].lazy,l,mid);
		lazy_add(rid,t[id].lazy,mid+1,r);
		t[id].lazy=0;
	}
}
il void add(int id,int l,int r,int L,int R,int k)
{
	if(L<=l && r<=R)
	{
		lazy_add(id,k,l,r);
		return;
	}
	push_down(id,l,r);
	int mid=(l+r)>>1;
	if(L<=mid) add(lid,l,mid,L,R,k);
	if(R>mid) add(rid,mid+1,r,L,R,k);
	push_up(id);
}
il int query_s(int id,int l,int r,int L,int R)
{
	if(L<=l && r<=R) return t[id].s;
	push_down(id,l,r);
	int mid=(l+r)>>1,ret=0;
	if(L<=mid) upd(ret,query_s(lid,l,mid,L,R));
	if(R>mid) upd(ret,query_s(rid,mid+1,r,L,R));
	return ret;
}
il int query_s2(int id,int l,int r,int L,int R)
{
	if(L<=l && r<=R) return t[id].s2;
	push_down(id,l,r);
	int mid=(l+r)>>1,ret=0;
	if(L<=mid) upd(ret,query_s2(lid,l,mid,L,R));
	if(R>mid) upd(ret,query_s2(rid,mid+1,r,L,R));
	return ret;
}
il int C(int x,int y)
{
	if(x<y) return 0;
	return 1ll*jc[x]*fjc[y]%mod*fjc[x-y]%mod;
}
int qpow(int x,int y)
{
	int ret=1;
	while(y)
	{
		if(y&1) ret=1ll*ret*x%mod;
		x=1ll*x*x%mod;y>>=1;
	}
	return ret;
}
signed main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	int n,m;fin>>n>>m;
	jc[0]=fjc[0]=jc[1]=fjc[1]=inv[1]=pow2[0]=1;pow2[1]=2;
	for(int i=2;i<=n;i++)
	{
		jc[i]=1ll*jc[i-1]*i%mod;
		inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;
		fjc[i]=1ll*fjc[i-1]*inv[i]%mod;
		pow2[i]=pow2[i-1]*2ll%mod;
	}
	f[0]=1;
	for(int i=1;i<n;i++) f[i]=(f[i-1]+1ll*(pow2[i+1]-1)*inv[i+1])%mod;
	for(int i=0;i<n-1;i++) g[i]=((long long)pow2[i+2]-1+mod-f[i+1])%mod*inv[i+1]%mod*inv[i+2]%mod;
	for(int i=1;i<n;i++) f[i]=1ll*f[i]*inv[i+1]%mod;
	while(m--)
	{
		int op,l,r;fin>>op>>l>>r;
		if(op==1)
		{
			int k;fin>>k;
			add(1,1,n,l,r,k);
		}
		else
		{
			
			int s1=query_s(1,1,n,l,r),s2=query_s2(1,1,n,l,r);
			int val1=1ll*inv[r-l+1]*(pow2[r-l+1]+mod-1)%mod,val2=0,val3=f[r-l];
			if(r-l>0) val2=g[r-l-1];
			int ans=0;
			ans=(ans+1ll*s2*val1)%mod;
			ans=(ans-(1ll*s1*s1-s2+mod)%mod*val2%mod+mod)%mod;
			ans=(ans-1ll*s2*val3%mod+mod)%mod;
			fout<<ans<<"\n";
		}
	}
	return 0;
}

P3934 炸脖龙 I

看到这一大坨子幂次第一反应就是欧拉降幂,使用树状数组维护每一位上的值,然后使用欧拉降幂就能过了。需要注意的是递归时遇到1需要中断这个hack。
代码:

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ll long long
struct IO
{
	static const int Size=(1<<21);
	char buf[Size],*p1,*p2;
	int st[105],Top;
	~IO(){clear();}
	il void clear(){fwrite(buf,1,Top,stdout);Top=0;}
	il char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,Size,stdin),p1==p2)?EOF:*p1++;}
	il void pc(const char c){Top==Size&&(clear(),0);buf[Top++]=c;}
	il IO& operator >>(char& c){while(c=gc(),c==' ' || c=='\n' || c=='\r');return *this;}
	template<typename T>il IO& operator >>(T& x)
	{
		x=0;bool f=0;char c=gc();
		while(!isdigit(c)){if(c=='-') f=1;c=gc();}
		while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
		f?x=-x:0;
		return *this;
	}
	il IO& operator >>(string& s)
	{
		s="";char c=gc();
		while(c==' ' || c=='\n' || c=='\r') c=gc();
		while(c!=' ' && c!='\n' && c!='\r' && c!=EOF) s+=c,c=gc();
		return *this;
	}
	il IO& operator <<(const char c){pc(c);return *this;}
	template<typename T> il IO& operator <<(T x)
	{
		if(x<0) pc('-'),x=-x;
		do st[++st[0]]=x%10,x/=10;while(x);
		while(st[0]) pc(st[st[0]--]+'0');
		return *this;
	}
	il IO& operator <<(const string s){for(auto c:s) pc(c);return *this;}
	il IO& operator <<(const char* c){for(int i=0;c[i];i++) pc(c[i]);return *this;}
} fin,fout;
const int N=500010,V=20000010;
bool St;
int phi[V],n,m,prime[V],cnt;
bool vis[V];
struct BIT
{
    ll s[N];
    il void add(int l,int r,ll x)
    {
        for(int i=l;i<=n;i+=i&-i) s[i]+=x;
        for(int i=r+1;i<=n;i+=i&-i) s[i]-=x;
    }
    il ll query(int x)
    {
        ll ret=0;
        for(int i=x;i;i-=i&-i) ret+=s[i];
        return ret;
    }
} B;
bool Ed;
il int qpow(int x,int y,int mod)
{
    int ret=1;
    while(y)
    {
        if(y&1) ret=1ll*ret*x%mod;
        x=1ll*x*x%mod;y>>=1;
    }
    return ret;
}
il pair<int,bool> query_ans(int l,int r,int p)
{
	ll val=B.query(l);
    if(l==r || B.query(l+1)==1)
	{
		bool fl=0;
		if(val<p) fl=1;
		return {val%p,fl};
	}
    if(p==1) return {0,0};
    auto tmp=query_ans(l+1,r,phi[p]);
    if(!tmp.second) return {qpow(val%p,phi[p]+tmp.first,p),0};
    else
    {
    	bool fl=1;
    	__int128 now=1;
    	for(int i=1;i<=tmp.first;i++)
    	{
    		now*=val;
    		if(now>=phi[p])
    		{
    			fl=0;
    			break;
			}
		}
		if(fl) return {now,1};
		else return {qpow(val%p,tmp.first,p),0}; 
	}
}
il void init()
{
    for(int i=2;i<=V-10;i++)
    {
        if(!vis[i]) prime[++cnt]=i,phi[i]=i-1;
        for(int j=1;j<=cnt;j++)
        {
            ll tmp=1ll*prime[j]*i;
            if(tmp>V-10) break;
            vis[tmp]=1;
            if(i%prime[j]==0)
            {
                phi[tmp]=phi[i]*prime[j];
                continue;
            }
            phi[tmp]=phi[i]*(prime[j]-1);
        }
        // fout<<phi[i]<<" ";
    }
    // fout<<"\n";
}
signed main()
{
//	freopen("P3934_10.in","r",stdin);
//	freopen("chj.out","w",stdout);
    init();
	fin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        int a;fin>>a;
        B.add(i,i,a);
    }
    while(m--)
    {
        int op,l,r;
		ll x;fin>>op>>l>>r>>x;
        if(op==1) B.add(l,r,x);
        else fout<<query_ans(l,r,x).first<<"\n";
    }
	return 0;
}

P11620 TEST_34

问选一些数中选若干个数的异或最大值,第一反应是线性基,但线性基无法快速区间修改,所以可以考虑其差分数组的线性基,发现原数组\([l,r]\)的线性基和差分数组\([l+1,r]\)的线性基中插入原数组的第\(l\)个位置的数效果相同,所以只需要用线段树维护差分数组的线性基和差分数组的前缀和即可。
代码:

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define lid id<<1
#define rid id<<1|1
struct IO
{
	static const int Size=(1<<21);
	char buf[Size],*p1,*p2;
	int st[105],Top;
	~IO(){clear();}
	il void clear(){fwrite(buf,1,Top,stdout);Top=0;}
	il char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,Size,stdin),p1==p2)?EOF:*p1++;}
	il void pc(const char c){Top==Size&&(clear(),0);buf[Top++]=c;}
	il IO& operator >>(char& c){while(c=gc(),c==' ' || c=='\n' || c=='\r');return *this;}
	template<typename T>il IO& operator >>(T& x)
	{
		x=0;bool f=0;char c=gc();
		while(!isdigit(c)){if(c=='-') f=1;c=gc();}
		while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
		f?x=-x:0;
		return *this;
	}
	il IO& operator >>(string& s)
	{
		s="";char c=gc();
		while(c==' ' || c=='\n' || c=='\r') c=gc();
		while(c!=' ' && c!='\n' && c!='\r' && c!=EOF) s+=c,c=gc();
		return *this;
	}
	il IO& operator <<(const char c){pc(c);return *this;}
	template<typename T> il IO& operator <<(T x)
	{
		if(x<0) pc('-'),x=-x;
		do st[++st[0]]=x%10,x/=10;while(x);
		while(st[0]) pc(st[st[0]--]+'0');
		return *this;
	}
	il IO& operator <<(const string s){for(auto c:s) pc(c);return *this;}
	il IO& operator <<(const char* c){for(int i=0;c[i];i++) pc(c[i]);return *this;}
} fin,fout;
const int N=50010;
int n,a[N],c[N];
struct BIT
{
	int s[N];
	il void add(int x,int k)
	{
		for(int i=x;i<=n;i+=(i&-i)) s[i]^=k;
	}
	il int query(int x)
	{
		int ret=0;
		for(int i=x;i;i-=i&-i) ret^=s[i];
		return ret;
	}
} B;
struct XXJ
{
	int p[30];
	il void ins(int x)
	{
		for(int i=29;i>=0;i--)
		{
			if(x>>i&1)
			{
				if(p[i]) x^=p[i];
				else
				{
					p[i]=x;
					break;
				}
			}
		}
	}
	il int query_max(int v)
	{
		int ans=v;
		for(int i=29;i>=0;i--)
		{
			if(p[i] && (ans^p[i])>ans) ans^=p[i];
		}
		return ans;
	}
} www;
il XXJ merge(XXJ x,XXJ y)
{
	for(int i=0;i<=29;i++)
	{
		if(y.p[i]) x.ins(y.p[i]);
	}
	return x;
}
struct sgt
{
	XXJ w[N<<2];
	il void push_up(int id)
	{
		w[id]=merge(w[lid],w[rid]);
	}
	il void build(int id,int l,int r)
	{
		if(l==r)
		{
			w[id].ins(c[l]);
			return;
		}
		int mid=(l+r)>>1;
		build(lid,l,mid);
		build(rid,mid+1,r);
		push_up(id);
	}
	il void add(int id,int l,int r,int x,int k)
	{
		if(l==r)
		{
			c[l]^=k;
			w[id]=www;
			w[id].ins(c[l]);
			return;
		}
		int mid=(l+r)>>1;
		if(x<=mid) add(lid,l,mid,x,k);
		else add(rid,mid+1,r,x,k);
		push_up(id);
	}
	il XXJ query(int id,int l,int r,int L,int R)
	{
		if(L>R) return www;
		if(L<=l && r<=R) return w[id];
		int mid=(l+r)>>1;
		if(R<=mid) return query(lid,l,mid,L,R);
		else if(L>mid) return query(rid,mid+1,r,L,R);
		else return merge(query(lid,l,mid,L,R),query(rid,mid+1,r,L,R));
	}
} T;
signed main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	int q;fin>>n>>q;
	for(int i=1;i<=n;i++) fin>>a[i];
	for(int i=1;i<=n;i++) c[i]=a[i]^a[i-1];
	T.build(1,1,n);
	for(int i=1;i<=n;i++) B.add(i,c[i]);
	while(q--)
	{
		int op,l,r,v;fin>>op>>l>>r>>v;
		if(op==1)
		{
			T.add(1,1,n,l,v);
			B.add(l,v);
			if(r!=n) B.add(r+1,v),T.add(1,1,n,r+1,v);
		}
		else
		{
			XXJ tmp=T.query(1,1,n,l+1,r);
			tmp.ins(B.query(l));
			fout<<tmp.query_max(v)<<"\n";
		}
	}
	return 0;
}
posted @ 2026-04-30 15:50  stuart220_chen  阅读(16)  评论(1)    收藏  举报