• 【NOI Online 提高组】最小环


    (Solution)

    我们将序列分成几个互不干扰的环。(互不干扰就是一个环以 (k) 无论如何都到不了另一个环)

    可以证明,我们会将其分成 (gcd(n,k)) 个环,每个环会有 (frac{n}{gcd(n,k)}) 个数。(很多人的题解是这么写的,然而蒟蒻本蒻根本看不懂

    我们接下来尝试证明一下:

    首先,如果是一个环的话应该首尾相同。我们设每个环有 (x) 个数。那么就有:(kxequiv0 (mod n))

    我们用 (gcd(n,k))(n)(k) 划分成几个小格子,那么 (frac{n}{gcd(n,k)}) 就是 (n) 有几个这样的小格子。我们将其乘以 (k),肯定是满足 (k) 走几步是能达到的,那么对于 (n),相当是将 (frac{n}{gcd(n,k)}) 个小格子的容量由 (gcd(n,k)) 扩展到了 (k) 个,也是满足前面同余的需求的。(注意必须使之前小格子的容量为 (k) 的因数,这样才能保证倍增)

    接下来我们要保证的是每个环有 (frac{n}{gcd(n,k)}) 个数的时候那个环的每个数只能走一次。(其实这里描述并不准确,因为个数本身就是只出现一次的)

    这个其实很好证,因为 (gcd) 就是最大的公共因数,所以 (frac{n}{gcd(n,k)}) 就是最小的,即 (x)

    然后关于为什么是按顺序放的我就在这里放一个大佬的证明:点此看神仙

    个数固定的一定答案是一样的,我们搞一个记忆化就可以了。(毕竟一个数的因子个数并不多)

    详见代码。

    (Code)

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const int N = 2e5 + 5;
    
    ll a[N], memo[N], ans;
    int n, m, k; 
    
    int read() {
        int x = 0, f = 1; char s;
        while((s = getchar()) > '9' || s < '0') if(s == '-') f = -1;
        while(s >= '0' && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
        return x * f;
    }
    
    int gcd(const int a, const int b) {
    	if(! b) return a;
    	return gcd(b, a % b);
    }
    
    int main() {
    	n = read(), m = read();
    	for(int i = 1; i <= n; ++ i) a[i] = read();
    	sort(a + 1, a + n + 1);
    	while(m --) {
    		k = read();
    		ans = 0;
    		if(k == 0 || n == 1) {
    			for(int i = 1; i <= n; ++ i) ans += a[i] * a[i];
    			printf("%lld
    ", ans);
    			continue;
    		}
    		int t = gcd(n, k), per = n / t;
    		if(memo[per]) {printf("%lld
    ", memo[per]); continue;}
    		for(int i = 1; i <= n; i += per) {
    			for(int j = 0; j < per - 2; ++ j) ans += a[i + j] * a[i + j + 2];//按顺序取,相当是 min,min+2...min+3,min+1 (这是个环)
    			ans += a[i] * a[i + 1] + a[i + per - 1] * a[i + per - 2];//取min与min+1,max与max-1
    		}
    		printf("%lld
    ", ans);
    		memo[per] = ans;
    	}
    	return 0;
    } 
    
  • 相关阅读:
    java8 parallel并行处理实战
    java相关技术问答(二)
    [安卓基础] 007.管理Activity的生命周期
    [Python基础]009.os模块(1)
    [Objective-C] 012_数据持久化_XML属性列表,NSUserDefaults
    SD.Team团队人物形象
    读Pyqt4教程,带你入门Pyqt4 _013
    [Objective-C] 011_数据持久化_NSKeyedArchiver
    [Objective-C] 010_Foundation框架之NSSet与NSMutableSet
    [JavaWeb基础] 007.Struts2的配置和简单使用
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/12456259.html
Copyright © 2020-2023  润新知