zoukankan      html  css  js  c++  java
  • [cf 1208G] Polygons

    题意

    在圆周上画出(k)个内接正多边形,要求(k)个正多边形边数不同,且最大的边数不超过(n),使得总顶点数最小。

    题解

    神仙题反映了我不会数学的事实。
    考虑如果选了一个正(n)边形,那么必定会选择满足(m | n)的正(m)边形。
    在考虑到最优的方案中,一定会让所有多边形共同一个点。
    考虑这个点为(O),设圆周长为1,则正(n)边形上的点到点(O)的圆上距离为

    [frac{0}{n}, frac{1}{n}, frac{2}{n}, ldots, frac{n - 1}{n} ]

    考虑因为选了正(n)边形时,一定会选择满足(m | n)的正(m)边形。
    这相当于正(n)边形独自产生的贡献是分母为(n)的最简真分数的个数(除去(frac{0}{n}))。
    这样,为了选出(k)个正多边形,就要让选出的正多边形独自产生的贡献和最小。
    这样只要排个序取前(k)小求和即可。
    需要注意的是,由于没有“一边形”和“二边形”,但是它们依然符合我们上面的类比分析。
    所以就可以令“一边形”的贡献为1(代表(O),即(frac{0}{n})),“二边形”的贡献为1(即(frac{1}{2}))。
    (k > 1)时,它们的贡献要囊括进来(在(k = 1)时,“二边形”不会产生贡献),但是由于没有“一边形”,“二边形”这种东西,所以不能算进(k)个正多边形里面。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1e6 + 5;
    int n, k; long long ans;
    int p[N], phi[N]; bool vis[N];
    vector <int> coe;
    void sieve () {
    	for (int i = 2; i <= n; ++i) {
    		if (!vis[i]) {
    			p[++p[0]] = i;
    			phi[i] = i - 1;
    		}
    		for (int j = 1; j <= p[0] && i * p[j] <= n; ++j) {
    			vis[i * p[j]] = 1;
    			if (i % p[j] == 0) {
    				phi[i * p[j]] = phi[i] * p[j];
    				break;
    			}
    			phi[i * p[j]] = phi[i] * (p[j] - 1);
    		}
    	}
    }
    
    int main () {
    	cin >> n >> k, sieve();
    	if (k == 1) {
    		return puts("3"), 0;
    	}
    	for (int i = 3; i <= n; ++i) {
    		coe.push_back(phi[i]);
    	}
    	sort(coe.begin(), coe.end());
    	for (int i = 0; i < k; ++i) {
    		ans += coe[i];
    	}
    	cout << ans + 2 << endl;
    	return 0;
    }
    
  • 相关阅读:
    MySQL令人咋舌的隐式转换
    MySQL 数据库基础(二)(MySQL 服务基础与使用 MySQL 数据库)
    以友盟+U-Push为例,深度解读消息推送的筛选架构解决方案应用与实践
    逆向工程,调试Hello World !程序(更新中)
    520了,用32做个简单的小程序
    postgresql 数据库 update更新慢的原因(已解决)
    面试题单例模式的五种写法(枚举妙用)
    人工智能能力提升指导总结
    数据结构-队列(2)-循环队列
    数据结构-队列(1)
  • 原文地址:https://www.cnblogs.com/psimonw/p/11615363.html
Copyright © 2011-2022 走看看