24.2.14-CLYZ

上午摸鱼 听课,下午打比赛。
又遇到了一点点小小的账号问题。

[恶意魔印]

题意: Q Q Q 组询问,给定 n , m , a n,m,a n,m,a,对于对于所有满足 1 ≤ i ≤ n 1 \le i \le n 1in 1 ≤ j ≤ m 1 \le j \le m 1jm 1 ≤ g c d ( i , j ) ≤ a 1 \le gcd(i,j) \le a 1gcd(i,j)a 的有序数对 ( i , j ) (i,j) (i,j),求出 l c m ( i , j ) lcm(i,j) lcm(i,j) 之和,对 1 0 9 + 7 10^9+7 109+7 取模。

对于 15 % 15\% 15% 的数据, Q = 1 Q=1 Q=1 n , m , a ≤ 5 × 1 0 3 n,m,a \le 5 \times 10^3 n,m,a5×103
对于 50 % 50\% 50% 的数据, Q = 1 Q=1 Q=1 n , m , a ≤ 5 × 1 0 5 n,m,a \le 5 \times 10^5 n,m,a5×105
对于 100 % 100\% 100% 的数据, Q ≤ 1 0 4 Q \le 10^4 Q104 n , m , a ≤ 5 × 1 0 5 n,m,a \le 5 \times 10^5 n,m,a5×105

[考场]

一眼就知道一定和数学有关,不是推公式就是反演。
然后就不会了,想了半个小时暴力草草走人。

[正解]

你是数学FW?我也是!
所以看题解推式子花了我一个小时。

一些前置知识

莫比乌斯函数:
μ ( d ) = { 1 ( d = 1 ) ( − 1 ) k ( d = p 1 p 2 p 3 . . . p k , p i 为互异素数 ) 0 ( 其它情况 ) \mu(d)=\begin{cases} 1(d=1) \\ (-1)^k (d=p_1p_2p_3...p_k,p_i为互异素数)\\0 (其它情况) \end{cases} μ(d)= 1(d=1)(1)k(d=p1p2p3...pk,pi为互异素数)0(其它情况)
狄利克雷卷积:
( f ∗ g ) ( n ) = ∑ d ∣ n f ( d ) g ( n d ) (f*g)(n)=\sum_{d|n}f(d)g(\frac{n}{d}) (fg)(n)=dnf(d)g(dn)
常见推论:

  1. d ( n ) = ∑ d ∣ n 1 d(n)=\sum_{d|n}1 d(n)=dn1 d = 1 ∗ 1 d=1*1 d=11
  2. σ ( n ) = ∑ d ∣ n d \sigma(n)=\sum_{d|n}d σ(n)=dnd σ = I d ∗ 1 \sigma =Id*1 σ=Id1
  3. φ ( n ) = ∑ d ∣ n μ ( d ) n d \varphi(n)=\sum_{d|n}\mu(d)\frac{n}{d} φ(n)=dnμ(d)dn φ = μ ∗ I d \varphi=\mu*Id φ=μId
  4. ε ( n ) = ∑ d ∣ n μ ( d ) \varepsilon(n)=\sum_{d|n}\mu(d) ε(n)=dnμ(d) ε = μ ∗ 1 \varepsilon=\mu*1 ε=μ1
由(3),我们有 ∑ d ∣ n μ ( d ) = [ n = 1 ] \sum_{d|n}\mu(d)=[n=1] dnμ(d)=[n=1]
推式子

∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) ≤ a ] ⋅ l c m ( i , j ) \sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)\le a]\cdot lcm(i,j) i=1nj=1m[gcd(i,j)a]lcm(i,j)
看起来 [ ] [] [] 内的东西不太好处理,不如再加一层循环?
∑ d = 1 a 1 d ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = d ] ⋅ i j \sum_{d=1}^{a}\frac{1}{d}\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)=d] \cdot ij d=1ad1i=1nj=1m[gcd(i,j)=d]ij
d d d 提出来?
∑ d = 1 a d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ [ g c d ( i , j ) = 1 ] ⋅ i j \sum_{d=1}^{a}d\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}[gcd(i,j)=1] \cdot ij d=1adi=1dnj=1dm[gcd(i,j)=1]ij
由上面加粗的公式,我们把 [ ] [] [] 扔掉
∑ d = 1 a d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i j ∑ p ∣ g c d ( i , j ) μ ( p ) \sum_{d=1}^{a}d\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor} ij \sum_{p|gcd(i,j)}\mu(p) d=1adi=1dnj=1dmijpgcd(i,j)μ(p)
把中间两个循环展开,用求和公式代替( S ( n ) = n ( n + 1 ) 2 S(n)=\frac{n(n+1)}{2} S(n)=2n(n+1))
∑ d = 1 a d ∑ p μ ( p ) ⋅ p 2 ⋅ S ( ⌊ n p d ⌋ ) ⋅ S ( ⌊ m p d ⌋ ) \sum_{d=1}^{a}d\sum_{p}\mu(p)\cdot p^2\cdot S(\lfloor \frac{n}{pd}\rfloor)\cdot S(\lfloor \frac{m}{pd}\rfloor) d=1adpμ(p)p2S(⌊pdn⌋)S(⌊pdm⌋)
T = p d T=pd T=pd,继续化简
∑ T = 1 S ( ⌊ n T ⌋ ) ⋅ S ( ⌊ m T ⌋ ) ⋅ ∑ 1 ≤ d ≤ a , d ∣ T T 2 d μ ( T d ) \sum_{T=1} S(\lfloor \frac{n}{T}\rfloor)\cdot S(\lfloor \frac{m}{T}\rfloor)\cdot \sum_{1 \le d \le a,d|T}\frac{T^2}{d}\mu(\frac{T}{d}) T=1S(⌊Tn⌋)S(⌊Tm⌋)1da,dTdT2μ(dT)

如何维护

将询问离线, a a a 从小到大排序处理。
对于 T 2 d μ ( T d ) \frac{T^2}{d}\mu(\frac{T}{d}) dT2μ(dT)用树状数组维护,对于每一个询问,整除分块去做(莫比乌斯反演老伙伴了)。
注意时时刻刻取模。(感谢 CQR DALAO)

代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,M=1e5,mod=1e9+7;
typedef long long LL;
struct node
{
	int n,m,a,id;
}q[N];
int cmpA(node x,node y){return x.a<y.a;}
inline LL S(int x){return (1LL*x*(x+1)/2LL)%mod;}
inline LL P(LL x){return ((x<0)?(((x%mod)+mod)%mod):(x%mod));}
inline void gmod(LL &x,LL y){x=(x+y)%mod;}
LL res[N],tr[N];
inline int lowbit(int x){return x&(-x);}
inline void modify(int x,LL v){for(;x<=M;x+=lowbit(x))gmod(tr[x],v);}
inline LL query(int x)
{
	LL res=0;
	for(;x;x-=lowbit(x))gmod(res,tr[x]);
	return res;
}
int primes[N],st[N],cnt;
LL mu[N];
void init()
{
    mu[1]=1LL;
    for(int i=2;i<=M;i++)
    {
        if(!st[i])
        {
            primes[cnt++]=i;
            mu[i]=-1;
        }
        for(int j=0;primes[j]*i<=M;j++)
        {
            st[primes[j]*i]=1;
            if(i%primes[j]==0)break;
            mu[primes[j]*i]=-mu[i];
        }
    }
    for(int i=1;i<=M;i++)mu[i]=P(1LL*mu[i]*(LL)i%mod*(LL)i%mod);
}
void work(int id)
{
	int la=q[id-1].a;
	int nn=q[id].n,nm=q[id].m,na=q[id].a;
	for(int i=la+1;i<=na;i++)
	{
		for(int T=i;T<=M;T+=i)modify(T,1LL*i*mu[T/i]%mod);
	}
	LL ans=0;
	for(int l=1,r;l<=nn;l=r+1)
	{
		r=min(nn/(nn/l),nm/(nm/l));
		gmod(ans,1LL*S(nn/l)*S(nm/l)%mod*P(query(r)-query(l-1))%mod);		
		ans=P(ans);
	}
	res[q[id].id]=ans;
}
int main()
{
	freopen("sum.in","r",stdin);
	freopen("sum.out","w",stdout);
	int T;
	scanf("%d",&T);
	for(int i=1;i<=T;i++)
	{
		scanf("%d%d%d",&q[i].n,&q[i].m,&q[i].a);
		if(q[i].n>q[i].m)swap(q[i].n,q[i].m);
		q[i].id=i;
	}
	sort(q+1,q+T+1,cmpA);
	init();
	for(int i=1;i<=T;i++)work(i);
	for(int i=1;i<=T;i++)printf("%lld\n",res[i]);
	return 0;
}

[松鼠串门]

题意:给定一棵根为1的树,有 n n n 个节点,每个节点都有权值 a i a_i ai,有 m m m 操作,一个操作是在某节点 u u u 下面挂一个儿子,权值为 v v v ,还有一个操作是从某节点 u u u 开始向根走 d d d 步(超过根到根就停止),路上任意结点的异或和最大是多少。

对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 5 × 1 0 5 1 \le n \le 5\times 10^5 1n5×105 1 ≤ m ≤ 5 × 1 0 5 1 \le m \le 5\times10^5 1m5×105 0 ≤ a i < 2 64 0 \le a_i <2^{64} 0ai<264

[考场]

异或和最大?线性基!
然后……聪明 纸张的我直接暴力将路径上的点加入线性基。

[正解]

感谢CYC&CYE DALAO
在这题之前,您可能需要了解这题,我们需要借鉴一些东西。
首先,我们发现插入操作完全对答案是没有影响的,不妨直接先插入后处理询问。
设插入完后有 n n n 个点,某个点坐标为 i i i,父亲为 p a r i par_i pari
我们建立 n n n 个线性基,对于第 i i i 个线性基,直接继承 p a r i par_i pari 的线性基。
至于插入操作,我们记录深度,如果当前位置不空,比较深度,将深度大的留下,深度小的继续下传。
查询时,注意取出的深度不能超过题目要求的 d d d 步就可以了。

代码
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N=1e6+5;
#define x first
#define y second
int n,m;
vector<pair<int,int> >q;
int d[N],par[N];
ULL w[N];
struct node
{
    ULL a[70];
    int d[70];
}H[N];
void insert(ULL a[],int d[],ULL x,int depth)
{
    for(int i=63;~i;i--)
    {
        if(x>>i&1)
        {
            if(!a[i])
            {
                a[i]=x;
                d[i]=depth;
                return;
            }
            else
            {
                if(depth>d[i])
                {
                    swap(a[i],x);
                    swap(d[i],depth);
                }
                x^=a[i];
            }
        }
    }
}
ULL query(ULL a[],int d[],int depth)
{
    ULL res=0;
    for(int i=63;~i;i--)
    {
        if(depth<=d[i]&&(res^a[i])>res)res^=a[i];
    }
    return res;
}
int main()
{
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d%llu",&par[i],&w[i]);
	while(m--)
	{
		int op,u;
		scanf("%d%d",&op,&u);
		if(!op)
		{
			int d;
			scanf("%d",&d);
			q.push_back({u,d});
		}
		else
		{
			ULL v;
			scanf("%llu",&v);
			par[++n]=u;
			w[n]=v;
		}
	}
	for(int i=1;i<=n;i++)
	{
	    d[i]=d[par[i]]+1;
	    memcpy(H[i].a,H[par[i]].a,sizeof H[i].a);
	    memcpy(H[i].d,H[par[i]].d,sizeof H[i].d);
	    insert(H[i].a,H[i].d,w[i],d[i]);
	}
	for(auto &[u,t]:q)printf("%llu\n",query(H[u].a,H[u].d,d[u]-t));
    return 0;
}

[寻找平衡]

OvO认为一些事情需要花费相同的时间去完成。
QwQ则觉得只需要让一些事情不比另一些事情完成的时间多就够了。
n n n 件事情,OvO 有 m 1 m_1 m1 个要求,QwQ 有 m 2 m_2 m2 个要求。
如果原来有一件事情花费了 w w w 的时间,现在若是要花费 x x x 时间去完成它,那就得付出 ∣ w − x ∣ |w-x| wx 这么多的精力。最少需要花费多少的精力,才能同时满足两人的要求。

对于 100 % 100\% 100% 的数据, n , m 1 ≤ 500 n,m_1 \le 500 n,m1500 m 2 ≤ 1 0 5 m_2 \le 10^5 m2105,时间 ≤ 1 0 9 \le10^9 109

考场

把OvO的要求用并查集合并,QwQ的要求建图后缩点,最后拓扑排序DP。
然而写挂了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值