zoukankan      html  css  js  c++  java
  • cf1208G Polygons 欧拉函数

    链接

    cf
    给你两个正整数(n)(k),询问在一个圆上你最少需要几个点构才能造出(k)个边数小于等于(n)的正多边形

    思路

    深受迫害,所以写的详细一点,不会请留言。

    性质1

    考虑加进一个(x)边形。那么他的因子(d)一定在他之前加进来了.
    因为(d)可以完全由(x)的点表现出来。
    如果没加(d),那么加(d)显然比加(x)优秀(显然)。

    性质2

    两个图形,让他们尽量多的重合些点是好的。
    那两个图形能重合多少点呢?答案显然是固定的。
    两个图形让他们一个点重合,即可得到最好的。
    因为是正多边形,所以随便重合一个点,重合的情况都是一样的。
    即最优的答案。
    所以我们加入的(k)个正多边形都重合到一个点上,设这个点为(0)点。

    联系起来

    (x)在圆上,假设他的点为(frac{0}{x},frac{1}{x}……frac{x-1}{x})
    (part2)可以知道,0这个点上每个图形都会经过。
    (part1)可以知道(x)的点上,他的因子在之前就会加入,所以他的因子及其倍数都是原先就有的(被覆盖过)。
    这个过程就是类似于暴力筛(phi)的过程,所以剩下的就是与他互质的数。
    所以一个正(x)边形的贡献就是(phi(x)).
    找出(k)个最小的(phi)就行了
    其实这个题就是俄罗斯数学竞赛的题目....我同桌给我讲过类似的证明,忘记了(菜)。

    代码

    因为1,2不是正x边形,所以不能选为k变形

    #include <bits/stdc++.h>
    using namespace std;
    const int _=1e6+7,limit=1e6;
    int phi[_];
    void Euler() {
    	for(int i=1;i<=limit;++i) phi[i]=i;
    	for(int i=2;i<=limit;++i) {
    		if(phi[i]==i) {
    			phi[i]=i-1;
    			for(int j=i+i;j<=limit;j+=i)
    				phi[j]=(phi[j]/i)*(i-1);
    		}
    	}
    }
    std::vector<int> ans;
    int main() {
    	Euler();
    	int n,k;
    	cin>>n>>k;
    	if(k==1) return puts("3"),0;
    	for(int i=3;i<=n;++i) ans.push_back(phi[i]);
    	sort(ans.begin(),ans.end());
    	long long tot=0;
    	for(int i=0;i<k;++i) tot+=ans[i];
    	cout<<tot+2<<"
    ";
    	return 0;
    }
    
    
  • 相关阅读:
    操作系统(一) 操作系统的概念
    数据结构(六) 排序
    数据结构(五) 查找和哈希表
    数据结构(三) 树和二叉树,以及Huffman树
    数据库简述(以MySQL为例)
    Java中的UDP应用
    Java线程池应用
    Java定时器应用
    JavaSE项目之聊天室swing版
    用LinkedList集合演示栈和队列的操作
  • 原文地址:https://www.cnblogs.com/dsrdsr/p/11428182.html
Copyright © 2011-2022 走看看