4.7省选模拟

\(4.7\)省选模拟

\(T1\)

谴责出题人不给线性筛\(70pts...\)

推到了一半

\(sgcd(i,j)\)\(i,j\)的第二小公约数

\(\large\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}sgcd(i,j)^k\)

我按莫比乌斯反演的套路推导,大概推了个这个式子

\(\large\sum_{d=1}^n num[d]^k\sum_{p=1}^{\frac{n}{d}}\mu(p)\lfloor\frac{n}{dp}\rfloor^2\)

\(\large\sum_p\mu(p)\sum_{d=1}^{\frac{n}{p}}num[d]^k\lfloor\frac{n}{dp}\rfloor^2\)

然后考完之后发现从倒数第二步推错了,最后一步是转化为\(\varphi,\)惯性思维直接把\(\mu\)写进去了

最后式子应该这样

\(\large\sum_{d=1}^n num[d]^k\times ((2\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\varphi(i))-1)\)

至于为什么能转化成这个,因为\(\varphi(n)\)的定义就是比\(i\)小与\(i\)互质的个数,行吧,思路完全偏移了

后边直接\(sb\)杜教筛套一套,前面的,嗯,考场上只会线性做法

考虑这个东西也是个积性函数,所以用\(Min25,\)貌似不太能\(PN\)

\(G_i=\sum_{j=2}^if(j)^k\)

\(s(x)=x^k\)

\(g_{i,j}=\sum_{k=1}^i[k\in P||minp(k)>P_j]s(k)\)

\(\sum s(x)[minp(x)=P_j,minp(\frac{x}{P_j})>=P_j]\)这个就是满足条件的\(f(x)^k\)

\(T2\)

考虑如何计算所有简单路径的颜色数

那么正难则反,考虑既然一种颜色只能算一次,我们考虑有多少路径包含这种颜色就好了,那么就用总的路径\(-\)不经过这种颜色路径\(=\)经过这个颜色路径,这些颜色在这些路径都贡献\(1,\)那么就好了

这个直接使用\(LCT\)维护,然后处理的话直接修改俩颜色就好了,考场上想处理简单路径来着,写了个假算法(大哭)

#include<bits/stdc++.h>
#define ll long long
#define MAXN 1000005
using namespace std;
vector<int>cx[MAXN],cy[MAXN],cz[MAXN];
int head[MAXN],nxt[MAXN],fa[MAXN],to[MAXN],tot=0,n,m;
int f[MAXN],sz[MAXN],ch[MAXN][2],sz1[MAXN],col[MAXN];
ll sz2[MAXN],dt[MAXN],ans=0;
ll P(int a)
{
	return 1ll*a*a;
}
void add(int a,int b)
{
	nxt[++tot]=head[a];
	to[tot]=b;
	head[a]=tot;
}
void adda(int a,int b,int c,int d)
{
	cx[a].push_back(b);
	cy[a].push_back(c);
	cz[a].push_back(d);
}
void DFS(int u)
{
	for(int i=head[u];i;i=nxt[i]) 
    {
    	if(fa[u]!=to[i]) fa[to[i]]=u,DFS(to[i]);
	}
}
bool isrt(int x)
{
	return (ch[f[x]][0]!=x)&(ch[f[x]][1]!=x);
}
void pushup(int x)
{
	sz[x]=sz1[x]+sz[ch[x][0]]+sz[ch[x][1]]+1; 
}
bool son(int x)
{
	return x==ch[f[x]][1];
}
void rotate(int x)
{
	int a=f[x],b=f[a],c=son(x),d=son(a),e=ch[x][!c];
	if(!isrt(a)) ch[b][d]=x;ch[x][!c]=a;ch[a][c]=e;
	if(e) f[e]=a;f[a]=x;f[x]=b;
	pushup(a);
}
void splay(int x)
{
	int b,c;
	while(!isrt(x))
	{
		b=f[x];c=f[b];
		if(!isrt(b)) {
			if(son(b)==son(x)) rotate(b);
			else rotate(x);
		}
		rotate(x);
	}
	pushup(x);
}
void access(int x)
{
	for(int y=0;x;y=x,x=f[x])
	{
		splay(x);
		sz1[x]+=sz[ch[x][1]]-sz[y];
		sz2[x]+=P(sz[ch[x][1]])-P(sz[y]);
		ch[x][1]=y;
		pushup(x);
	}
}
int getroot(int x)
{
	access(x);splay(x);
	while(ch[x][0]) x=ch[x][0];
	splay(x);
	return x;
}
void link(int u)
{
	int v=fa[u];
	splay(u);
	ans-=P(sz[ch[u][1]]);
	ans-=sz2[u];
	int w=getroot(v);
	access(u);splay(w);
	ans-=P(sz[ch[w][1]]);
	f[u]=v;
	splay(v);
	sz1[v]+=sz[u];sz2[v]+= P(sz[u]);
	pushup(v);
	access(u);splay(w);
	ans+=P(sz[ch[w][1]]);
}
void cut(int u)
{
	int v=fa[u];
    access(u);
	ans+=sz2[u];
	int w=getroot(v);
	access(u);splay(w);
	ans-=P(sz[ch[w][1]]); 
	splay(u);
	ch[u][0]=f[ch[u][0]]=0;
	pushup(u);splay(w);
	ans+=P(sz[ch[w][1]]);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&col[i]),adda(col[i],i,1,0);
	for(int i=1,u,v;i<n;i++) 
	{
		scanf("%d%d",&u,&v);
		add(u,v);
		add(v,u);
	}
	for(int i=1;i<=n+1;i++) sz[i]=1;
	fa[1]=n+1;
	DFS(1);
	for(int i=1,x,y;i<=m;i++) 
	{
		scanf("%d%d",&x,&y);
		adda(col[x],x,-1,i);
		adda(col[x]=y,x,1,i);
	}
	ll las=1ll*n*n;
	for(int i=1;i<=n;i++) link(i);
	for(int i=1;i<=n;i++) 
	{
		for(int j=0;j<cx[i].size();j++) 
		{
			int x=cx[i][j],y=cy[i][j],z=cz[i][j];
			if(y==-1) link(x);
			else cut(x);
			dt[z]-=ans-las;
			las=ans;
		}
		for(int j=cx[i].size()-1;j>=0;j--)
		{
			int x=cx[i][j],y=cy[i][j],z=cz[i][j];
			if(y==-1) cut(x);
			else link(x);
		}
		las=ans;
	}
	printf("%lld\n",ans=dt[0]);
	for(int i=1;i<=m;i++) printf("%lld\n",ans+=dt[i]);
	return 0;
}

\(T3\)

两个性质

\(f(a,b)=f(b,a)\)那么一半是一样的

后面那个性质确实没有看懂...

\(b\times f(a,a+b)=(a+b)\times f(a,b)\)

可以化成

\(\frac{f(a,b)}{a\times b}=\frac{f(a,a+b)}{a\times(a+b)}\)

类似辗转相除法的求\(\gcd\)过程,我们这样一直求到最后

\(\frac{f(a,b)}{a\times b}=\frac{f(G,G)}{G\times G}\)

就是相当于,\(G\)相同的位置一块变化

\(Ans=\sum_{i=1}^k\sum_{j=1}^k f(i,j)\)

\(Ans=\sum_{d=1}^{k}f(d,d)\sum_{d|i}\sum_{d|j}\frac{i\times j}{d^2}[gcd(i,j)=d]\)

\(Ans=\sum_{d=1}^{k}f(d,d)\sum_{k/d}\sum_{k/d}{i\times j}[gcd(i,j)=1]\)

直接对\(k/d\)分块,然后暴力修改,使用分块大法

#include <bits/stdc++.h>
#define mod 1000000007
#define MAXN 4000010
#define ll long long
using namespace std;
bool v[MAXN];
int n,m,T,cnt,prm[MAXN],bel[MAXN];
ll ans,phi[MAXN],f[MAXN],g[MAXN],sum[2][MAXN];
void findprm(int n)
{
	phi[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!v[i]) prm[++cnt]=i,phi[i]=i-1;
		for(int j=1;j<=cnt;j++)
		{
			if(i>n/prm[j]) break;
			v[i*prm[j]]=1; 
			phi[i*prm[j]]=phi[i]*(prm[j]-1);
			if(i%prm[j]==0)
			{
				phi[i*prm[j]]=phi[i]*prm[j];
				break;
			}
		}
	}
}
ll my_pow(ll a,ll b)
{
	ll res=1;
	while(b)
	{
		  if(b&1)
		  {
		  	 res=(res*a)%mod;
		  }
		  a=(1ll*a*a)%mod;
		  b>>=1;
	}
	return res;
}
int gcd(int x,int y)
{
	return y?gcd(y,x%y):x;
}
ll calc(int i)
{
	return (sum[0][bel[i]]+sum[1][i])%mod;
}
int main()
{
	scanf("%d%d",&m,&n);
	findprm(n);
	T=sqrt(n)+1;
	for (int i=1;i<=n;i++)
	{
		bel[i]=(i-1)/T+1;
		phi[i]=(phi[i-1]+phi[i]*i%mod*i)%mod;
		f[i]=1LL*i*i%mod;
		g[i]=(g[i-1]+f[i])%mod;
		sum[1][i]=(g[i]-g[(bel[i]-1)*T])%mod;
	}
	for (int i=1;i<=T;i++) sum[0][i]=g[(i-1)*T];
	for(int o=1;o<=m;o++)
	{
		int x,y,k; ll p;
		scanf("%d%d",&x,&y);
		scanf("%lld",&p);
		scanf("%d",&k);
		int d=gcd(x,y);
		p=p%mod*d%mod*d%mod*my_pow(x,mod-2)%mod*my_pow(y,mod-2)%mod;
		for(int i=bel[d]+1;i<=T;i++)
			sum[0][i]=(sum[0][i]+p-f[d])%mod;
		for(int i=d;i<=bel[d]*T;i++)
			sum[1][i]=(sum[1][i]+p-f[d])%mod;
		f[d]=p; ans=0;
		for(int l=1,r;l<=k;l=r+1)
		{
			r=k/(k/l);
			ans=(ans+(calc(r)-calc(l-1))*phi[k/l])%mod;
		}
		printf("%lld\n",(ans%mod+mod)%mod);
	}
	return 0;
}

posted @ 2022-04-07 16:48  Authentic_k  阅读(26)  评论(0编辑  收藏  举报