• 2022暑假“雅礼集训”Day2


    cyj 的场哦/qq/qq/qq

    考场 80+30+40 但感觉最后一题或者第一题是要做出来的……

    P5572 CmdOI2019 简单的数论题

    \[ \sum_{i=1}^n\sum_{j=1}^m \varphi(\frac{ij}{\gcd^2(i,j)})=\sum_{d=1}^n \sum_{i=1}^{[\frac nd]}\sum_{j=1}^{[\frac md]}\varphi(i)\varphi(j)[(i,j)=1] \\=\sum_{d=1}^n \sum_{k=1}^{[\frac nd]}\mu(k)\sum_{i=1}^{[\frac n{dk}]}\sum_{j=1}^{[\frac m{dk}]}\varphi(ik)\varphi(jk) =\sum_{T=1}^n \sum_{k|T}\mu(k)\sum_{i=1}^{[\frac nT]}\sum_{j=1}^{[\frac mT]}\varphi(ik)\varphi(jk) \]

    方便书写,我们定义 \(G(x,y)=\sum \limits_{i=1}^x \varphi(iy),S(x,y,z)=\mu(z)G(x,z)G(y,z)\)

    \[ Ans=\sum_{T=1}^n \sum_{k|T}\mu(k)G([\frac nT],k)G([\frac mT],k)=\sum_{T=1}^n \sum_{k|T}S([\frac nT],[\frac mT],k) \]

    为了数论分块,我们定义 \(H(x,y,z)=\sum\limits_{i=1}^z \sum\limits_{k|i} S(x,y,k)\),这样数论分块时的答案就是 \(H([\frac nT],[\frac mT],r)-H([\frac nT],[\frac mT],l-1)\)

    看着办预处理一点 \(H\) 再开个 O2 救过了……

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 1e9
    const int maxn=2e5+10;
    const int mod=23333;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    const int N=50000;
    const int B=72;
    int mu[maxn],phi[maxn],flg[maxn],pri[maxn],tot;
    inline int gcd(int x,int y){return !y?x:gcd(y,x%y);}
    vector<int>S[maxn],H[B+1][B+1],fac[N+5];
    inline int solve(int n,int m){
    	int res=0,R=0;
    	for(int l=1,r;l<=n&&l<=m;l=r+1){
    		r=min(n/(n/l),m/(m/l));
    		if((n/l)<=B&&(m/l)<=B)
    			res=(res+H[n/l][m/l][r]-H[n/l][m/l][l-1]+mod)%mod;
    		else R=r;
    	}//printf("%d\n",R);
    	for(int i=1;i<=R;i++)
    		for(auto x:fac[i])res=(res+mu[x]*S[x][n/i]*S[x][m/i])%mod;
    	return (res+mod)%mod;
    }
    int T,n,m;
    int main(){
    //	freopen("baryonyx.in","r",stdin);
    //	freopen("baryonyx.out","w",stdout);
    	mu[1]=phi[1]=1;
    	for(int i=2;i<=N;i++){
    		if(!flg[i])pri[++tot]=i,phi[i]=i-1,mu[i]=-1;
    		for(int j=1;j<=tot&&i*pri[j]<=N;j++){
    			flg[i*pri[j]]=1;
    			if(i%pri[j]==0){
    				mu[i*pri[j]]=0;
    				phi[i*pri[j]]=phi[i]*pri[j];
    				break;
    			}mu[i*pri[j]]=-mu[i];
    			phi[i*pri[j]]=phi[i]*(pri[j]-1);
    		}
    	}
    	for(int i=1;i<=N;i++){
    		int now=0;
    		for(int j=0;j<=N;j+=i){
    			now+=phi[j];now%=mod;
    			S[i].push_back(now);
    		}
    	}
    	for(int i=1;i<=N;i++)
    		if(mu[i]!=0)for(int j=i;j<=N;j+=i)fac[j].push_back(i);
    	for(int i=1;i<=B;i++)
    		for(int j=1;j<=B;j++){
    			H[i][j].resize(N/j+3);
    			for(int k=1;k<=N/j&&k<=N/i;k++){
    				int res=H[i][j][k-1];
    				for(auto x:fac[k])res=(res+mu[x]*S[x][i]*S[x][j])%mod;
    				H[i][j][k]=res;
    			}
    		}
    	T=read();
    	while(T--){
    		n=read(),m=read();
    		printf("%d\n",solve(n,m));
    	}return 0;
    }
    

    P5609 Ynoi2013 对数据结构的爱

    其实是不久前才看见的套路,现在就想不到了!对于区间 \([l,r]\)\(dp_k\) 表示要使在此区间中减 \(k\) 次进去时候的最小值。其余随便编。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define inf 1e16
    const int maxn=1e6+10;
    const int mod=1e9+7;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    int n,m,p,a[maxn],Sum[maxn<<2];
    vector<int>tr[maxn<<2];
    inline void build(int h,int l,int r){
    	tr[h].resize(r-l+3);
    	tr[h][0]=-inf;tr[h][r-l+2]=inf;
    	if(l==r){tr[h][1]=p-a[l],Sum[h]=a[l];return;}
    	int mid=(l+r)>>1,len=r-l+1;
    	int ll=mid-l+1,lr=r-mid,ls=(h<<1),rs=(h<<1|1);
    	build(h<<1,l,mid);build(h<<1|1,mid+1,r);
    	Sum[h]=Sum[h<<1]+Sum[h<<1|1];
    	//printf("l=%lld r=%lld\n",l,r);
    	for(int i=len,x=ll;i;--i){
    		while(x>i)x--;int flg=0;
    		while(!flg){
    			while(1){
    				if(x<0||i-x>lr)break;
    				int l1=tr[ls][x],r1=tr[ls][x+1]-1;
    				int l2=tr[rs][i-x]+p*x-Sum[ls],r2=tr[rs][i-x+1]+p*x-Sum[ls]-1; 
    				if(l1>r2||l2>r1)break;x--;flg=1;
    			}if(!flg)x--;
    		}x=x+1;
    		tr[h][i]=max(tr[ls][x],tr[rs][i-x]+p*x-Sum[ls]);
    		//printf("%lld ",tr[h][i]);
    	}//puts("");
    }
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define mkp make_pair
    inline pii query(int h,int l,int r,int x,int y,int sum,int cnt){
    	if(l>=x&&r<=y){
    		int pos=upper_bound(tr[h].begin(),tr[h].end(),sum)-tr[h].begin()-1;
    		return mkp(sum+Sum[h]-p*pos,cnt+pos);
    	}int mid=(l+r)>>1;
    	if(mid<x)return query(h<<1|1,mid+1,r,x,y,0,0);
    	if(mid>=y)return query(h<<1,l,mid,x,y,sum,cnt);
    	pii ls=query(h<<1,l,mid,x,y,sum,cnt);
    	return query(h<<1|1,mid+1,r,x,y,ls.fi,ls.se);
    }
    signed main(){
    //	freopen("spinosaurus.in","r",stdin);
    //	freopen("spinosaurus.out","w",stdout);
    	n=read(),m=read(),p=read();
    	for(int i=1;i<=n;i++)a[i]=read();
    	build(1,1,n);
    	for(int i=1,l,r;i<=m;i++){
    		l=read(),r=read();
    		printf("%lld\n",query(1,1,n,l,r,0,0).fi);
    	}
    	return 0;
    }
    
  • 相关阅读:
    TCP,IP,HTTP,SOCKET区别和联系
    添加Nginx为系统服务(设置开机启动)
    设计模式大全
    linux 命令行 光标移动技巧等
    Linux中ping命令
    TCP/IP协议 三次握手与四次挥手【转】
    Node 出现 uncaughtException 之后的优雅退出方案
    Google Protocol Buffers简介
    关于绝对路径和相对路径
    node定时任务——node-schedule模块使用说明
  • 原文地址:https://www.cnblogs.com/syzf2222/p/16487965.html
Copyright © 2020-2023  润新知