题解 CF1208G 【Polygons】

foreverlasting

2019-08-30 17:06:31

Solution

[推销博客](https://foreverlasting1202.github.io/2019/08/27/CF1208%E9%A2%98%E8%A7%A3/) ### G Polygons 题意:给出$n$和$k$,要求在圆上用最少的点数使得能够找到$k$个正多边形而且这$k$个正多边形的长度小于等于$n$,求最少的点数。$1\leq k\leq n-2\leq 10^6$。 做法:考虑如果选择一个数$x$(不考虑$1$和$2$的情况),则显然与它不互质的数都已经选过了(否则选不互质的数会更优),那么这个数的贡献就会是$\phi(x)$。因此给$\phi$排个序,找前$k$个就可以了。时间复杂度$O(nlogn)$。 code: ```cpp //2019.8.27 by ljz //email [email protected] //if you find any bug in my code //please tell me #include<bits/stdc++.h> using namespace std; #define res register int #define LL long long #define inf 0x3f3f3f3f #define INF 0x3f3f3f3f3f3f3f #define unl __int128 #define eps 5.6e-8 #define RG register #define db double #define pc(x) __builtin_popcount(x) //#define pc(x) __builtin_popcountll(x) typedef pair<int,int> Pair; #define mp make_pair #define fi first #define se second #define pi acos(-1.0) #define pb push_back #define ull unsigned LL #define gc getchar //inline char gc() { // static char buf[100000],*p1,*p2; // return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; //} inline int read() { res s=0,ch=gc(); while(ch<'0'||ch>'9')ch=gc(); while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=gc(); return s; } //inline int read() { // res s=0,ch=gc(),w=1; // while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=gc();} // while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=gc(); // return s*w; //} //inline LL Read() { // RG LL s=0; // res ch=gc(); // while(ch<'0'||ch>'9')ch=gc(); // while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=gc(); // return s; //} //inline LL Read() { // RG LL s=0; // res ch=gc(),w=1; // while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=gc();} // while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=gc(); // return s*w; //} //inline void write(RG unl x){ // if(x>10)write(x/10); // putchar(int(x%10)+'0'); //} inline void swap(res &x,res &y) { x^=y^=x^=y; } //mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); //clock_t start=clock(); //inline void ck(){ // if(1.0*(clock()-start)/CLOCKS_PER_SEC>0.1)exit(0); //} const int N=1e6+10; namespace MAIN{ int n,k; int prim[N/10],tot,phi[N]; bool vis[N]; inline void MAIN(){ phi[1]=1,n=read(),k=read(); for(res i=2;i<=n;i++){ if(!vis[i])prim[++tot]=i,phi[i]=i-1; for(res j=1;j<=tot&&prim[j]*i<=n;j++){ vis[prim[j]*i]=1; if(i%prim[j]==0){phi[prim[j]*i]=phi[i]*prim[j];;break;} phi[prim[j]*i]=phi[i]*(prim[j]-1); } } sort(phi+1,phi+n+1); RG LL ans=0; for(res i=1;i<=k+2;i++)ans+=phi[i]; printf("%lld\n",ans-(k==1)); } } int main(){ // srand(19260817); // freopen("signin.in","r",stdin); // freopen("signin.out","w",stdout); MAIN::MAIN(); return 0; } ```