• [武汉加油] [NOI Online 提高组]最小环


    结论题

    其实没那么难,只不过真的被附加说明给恶心到了。

    首先我们将相乘的数连边,能看出来会形成几个环,显然环与环之间互不影响。

    然后易证一共有 (gcd(n,k)) 个环,每个环里就有 (frac{n}{gcd(n,k)}) 个数,显然我们给每个环分配的数连续更优。

    关于一个环里怎么分配:我们 看样例/手玩可知 将所有的数从小到大排序依次塞入,左一个右一个最优,其实也很好理解,这样我们能将较大的数尽可能的挨在一起(考虑它是一个环)。

    然后发现时间复杂度并不对,我们可以记忆化一下答案,又因为我们用到的k只与 (gcd(n,k)) 有关,所以我们让 (k=gcd(n,k)) 。如果 (n)(sqrt n)个约数的话,时间复杂度就成了(O(nsqrt n)),但实际上达不到。

    注意$k imes 2=n $的情况.

    下面是考场代码,可能有点丑.

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    #define LL long long
    using namespace std;
    int n, m, k, t;
    const int N = 200010;
    int a[N];
    LL ans[N];
    inline int read()
    {
    	int res = 0; char ch = getchar(); bool XX = false;
    	for (; !isdigit(ch); ch = getchar())(ch == '-') && (XX = true);
    	for (; isdigit(ch); ch = getchar())res = (res << 3) + (res << 1) + (ch ^ 48);
    	return XX ? -res : res;
    }
    int GCD(int a, int b) {return b ? GCD(b, a % b) : a;}
    void solve1()
    {
    	while (m--)
    	{
    		k = read();
    		if (ans[k]) {printf("%lld
    ", ans[k]); continue;}
    		if (k == 0)
    		{
    			for (int i = 1; i <= n; ++i)ans[k] += (LL)a[i] * a[i];
    			printf("%lld
    ", ans[k]);
    			continue;
    		}
    		if (2 * k == n)
    		{
    			for (int i = 1; i <= n; i += 2)ans[k] += (LL)a[i] * a[i + 1];
    			ans[k] *= 2;
    			printf("%lld
    ", ans[k]);
    			continue;
    		}
    		t = n / GCD(n, k); //gcd 个环
    		for (int i = 1; i <= n; i += t)
    			for (int j = i, to = i + t - 1; j <= to - 1; ++j)
    			{
    				if (j == i)ans[k] += (LL)a[j] * a[j + 1] + (LL)a[j] * a[j + 2];
    				else if (j == to - 1)ans[k] += (LL)a[j] * a[j + 1];
    				else ans[k] += (LL)a[j] * a[j + 2];
    			}
    		printf("%lld
    ", ans[k]);
    	}
    }
    void solve2()
    {
    	while (m--)
    	{
    		k = read();
    		if (k == 0)
    		{
    			if (!ans[k])for (int i = 1; i <= n; ++i)ans[k] += (LL)a[i] * a[i];
    			printf("%lld
    ", ans[k]);
    			continue;
    		}
    		k = GCD(n, k);
    		if (ans[k]) {printf("%lld
    ", ans[k]); continue;}
    		if (2 * k == n)
    		{
    			for (int i = 1; i <= n; i += 2)ans[k] += (LL)a[i] * a[i + 1];
    			ans[k] *= 2;
    			printf("%lld
    ", ans[k]);
    			continue;
    		}
    		t = n / GCD(n, k); //gcd 个环
    		for (int i = 1; i <= n; i += t)
    			for (int j = i, to = i + t - 1; j <= to - 1; ++j)
    			{
    				if (j == i)ans[k] += (LL)a[j] * a[j + 1] + (LL)a[j] * a[j + 2];
    				else if (j == to - 1)ans[k] += (LL)a[j] * a[j + 1];
    				else ans[k] += (LL)a[j] * a[j + 2];
    			}
    		printf("%lld
    ", ans[k]);
    	}
    }
    int main()
    {
    // 	freopen("ring.in","r",stdin);
    // 	freopen("ring.out","w",stdout);
    	cin >> n >> m;
    	for (int i = 1; i <= n; ++i)a[i] = read();
    	sort(a + 1, a + 1 + n);
    	if (n <= 3000)solve1();
    	else solve2();
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    python ddt 传多个参数值示例
    Appium 输入 & 符号,实际输入&-
    curl 调用jenkins的api
    Android WebView的Js对象注入漏洞解决方案
    Could not find com.android.tools.build:gradle:1.3.0.
    react-native疑难
    win上搭建react-native android环境
    gradle大体内容
    android studio This client is too old to work with the working copy at
    sharedPreference
  • 原文地址:https://www.cnblogs.com/wljss/p/12434092.html
Copyright © 2020-2023  润新知