zoukankan      html  css  js  c++  java
  • 题解 P1891 【疯狂 LCM】

    [ans=sum_{i=1}^nlcm(i,n) ]

    [egin{aligned} ans & =sum_{i=1}^nlcm(i,n) \ & =sum_{i=1}^nfrac{icdot n}{gcd(i,n)} \ & =n imes sum_{i=1}^nfrac{i}{gcd(i,n)} \ & =n imessum_{i=1}^nisum_{d=1}^ifrac{[gcd(i,n)=d]}{d} \ & =n imes sum_{d|n}sum_{i=1}^{leftlfloordfrac{n}{d} ight floor}icdot[gcd(i,frac{n}{d})=1] end{aligned} ]

    我们看后面的东西


    [g(n)=sum_{i=1}^nicdot [gcd(i,n)=1] ]

    我们知道更相减损术

    [gcd(a,b)=gcd(a,a-b) ]

    所以

    [gcd(i,d)=1Leftrightarrow gcd(d-i,d)=1 ]

    所以

    对于每一个i,都有另一个d-i与其对应,而且两个数的和是个定值

    所以

    [g(n)=frac{varphi(n)}{2} imes d ]

    但是g(1)是个特例,所以要特别处理

    g出来了之后我们再预处理答案,核心代码如下

    for (int i = 1; i <= N; i++) {
    		for (int j = i; j <= N; j += i) {
    			S[j] += (g[i] * i + 1) >> 1;
    		}
    	}
    
    

    这样就可以做到了。

    #include<cstdio>
    #define Starseven main
    #define ll long long
    namespace lyt {
    	void read(int &x){
    	char ch=getchar();int re=0,op=1;
    	while(ch<'0'||ch>'9'){if(ch=='-') op=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){re=(re<<3)+(re<<1)+ch-'0';ch=getchar();}
    	x = re * op;
    	return ;
    	}
    	void read(long long &x){
    	char ch=getchar();long long re=0,op=1;
    	while(ch<'0'||ch>'9'){if(ch=='-') op=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){re=(re<<3ll)+(re<<1ll)+ch-'0';ch=getchar();}
    	x = re * op;
    	return ;
    	}
    	void write(int x){
    		if(x<0){putchar('-');x=-x;}
    		if(x>9) write(x/10);
    		putchar(x%10+'0');
    		return ;
    	}//记得自己加空格和换行 
    	void write(long long x){
    		if(x<0){putchar('-');x=-x;}
    		if(x>9) write(x/10);
    		putchar(x%10+'0');
    		return ;
    	}//记得自己加空格和换行
    	int max(int x,int y){return x<y?y:x;}
    	int min(int x,int y){return x<y?x:y;}
    	int abs(int x){return x<0?-x:x;}
    	long long max(long long x,long long y){return x<y?y:x;}
    	long long min(long long x,long long y){return x<y?x:y;}
    	long long abs(long long x){return x<0?-x:x;}
    	double abs(double x){return x<0?-x:x;}
    	void swap(int &a,int &b) {a ^= b ^= a ^= b;}
    	void swap(long long &a,long long &b) {a ^= b ^= a ^= b;}
    }using namespace lyt;
    const int N = 1e6;
    int prime[N + 20], num;
    ll S[N + 20], g[N + 20];
    bool vis[N + 20];
    
    void Init(void) {
    	g[1] = 1;
    	for (int i = 2; i <= N; i++) {
    		if(!vis[i]) {
    			g[i] = i - 1;
    			prime[++num] = i;
    		}
    		for (int j = 1; j <= num && prime[j] * i <= N; j++) {
    			int x = prime[j] * i;
    			vis[x] = true;
    			if(i % prime[j] == 0) {
    				g[x] = g[i] * prime[j];
    				break;
    			}
    			g[x] = g[i] * g[prime[j]];
    		}
    	}
    	return ;
    }
    
    int Starseven(void) {
    	int t;
    	read(t);
    	Init();
    	for (int i = 1; i <= N; i++) {
    		for (int j = i; j <= N; j += i) {
    			S[j] += (g[i] * i + 1) >> 1;//我这里没有特判1,而是用了一点小技巧
    		}
    	}
    	while(t--) {
    		int n;
    		read(n);
    		write(S[n] * n * 1ll);
    		puts("");
    	}
    	return 0;	
    }
    
  • 相关阅读:
    洛谷 P1019单词接龙
    洛谷 P1091合唱队列
    洛谷 P1141 01迷宫
    洛谷 P1101单词方阵
    NOIP要炸?
    洛谷 P1219八皇后
    洛谷 P1181数列分段Section I
    刷普及-刷爆了。。。。。。
    洛谷 P3952时间复杂度 (本地AC测评RE的伪题解)
    动态数码管
  • 原文地址:https://www.cnblogs.com/starseven/p/13560222.html
Copyright © 2011-2022 走看看