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;
}