Codeforces 851D Arpa and a list of numbers Round #432 (Div. 2
2017-09-06 11:53
666 查看
题意:
给你n个数,你有两个操作:
①将某个数删掉,消耗为x
②将某个数+1,消耗为y,这个操作可以对某个数多次使用
而你的目的是让最后n个数的Gcd不为1,求最小消耗
思路:
思路懒得打了,看下面这篇博客的吧
http://blog.csdn.net/mengxiang000000/article/details/77850732
我们知道,Gcd的结果是素数是最好的,所以我们首先筛出素数,1e6内的素数个数约为8w(8e4)个。
然后考虑对应数字是删除还是增添。很显然我们这里可以Dp去做,但是时间复杂度很爆炸,所以考虑X和Y两种操作之间的关系。
①不难想到,如果X<Y的话,我们就不用进行Y操作了。
②所以我们设定move=X/Y表示我们最多对一个数进行增添数字的次数,如果超过了这个次数,我们不如将其删除来的划算。
接下来考虑如何计算结果。首先我们肯定要O(8e4)去枚举答案,接下来考虑,既然我们已经知道了move这个信息,那么对于当前枚举的素数p,我们有一个区间【p,2p】的话,我们肯定能够通过move这个信息找到区间的一个分界点,使得【p~分界点】的数我们都将其删除,使得【分界点~2p】的数字都增添变成2p.
那么这里我们只要枚举出来一个素数p,然后每一次计算之后将区间移动p个长度即可。整体时间复杂度O(Len*LogLen)这里Len表示素数的个数。
具体实现细节都在代码的注释里
给你n个数,你有两个操作:
①将某个数删掉,消耗为x
②将某个数+1,消耗为y,这个操作可以对某个数多次使用
而你的目的是让最后n个数的Gcd不为1,求最小消耗
思路:
思路懒得打了,看下面这篇博客的吧
http://blog.csdn.net/mengxiang000000/article/details/77850732
我们知道,Gcd的结果是素数是最好的,所以我们首先筛出素数,1e6内的素数个数约为8w(8e4)个。
然后考虑对应数字是删除还是增添。很显然我们这里可以Dp去做,但是时间复杂度很爆炸,所以考虑X和Y两种操作之间的关系。
①不难想到,如果X<Y的话,我们就不用进行Y操作了。
②所以我们设定move=X/Y表示我们最多对一个数进行增添数字的次数,如果超过了这个次数,我们不如将其删除来的划算。
接下来考虑如何计算结果。首先我们肯定要O(8e4)去枚举答案,接下来考虑,既然我们已经知道了move这个信息,那么对于当前枚举的素数p,我们有一个区间【p,2p】的话,我们肯定能够通过move这个信息找到区间的一个分界点,使得【p~分界点】的数我们都将其删除,使得【分界点~2p】的数字都增添变成2p.
那么这里我们只要枚举出来一个素数p,然后每一次计算之后将区间移动p个长度即可。整体时间复杂度O(Len*LogLen)这里Len表示素数的个数。
具体实现细节都在代码的注释里
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; int a[3000000]; long long num[3000000]= {0}; long long ssum[3000000]= {0}; int main() { int n,x,y; // cout<<__gcd(1000000,5000001)<<endl; while(cin>>n>>x>>y) { int p = x/y; long long ans = (long long)x*n; memset(num,0,sizeof(num)); memset(ssum,0,sizeof(ssum)); int data; for(int i=1; i<=n; i++) { scanf("%d",&data); num[data]++; ssum[data]+=data; } for(int i=1; i<=2000000; i++)//配合下面计算 { num[i]+=num[i-1]; ssum[i]+=ssum[i-1]; } for(int i=2; i<=1000000; i++) //枚举这一群数的gcd, //理论上都是素数,但为了简便,枚举了所有数 { long long sum = 0,nsum1,nsum2,vsum; for(int j=i; j<=1000000+i; j+=i)//此处要特别注意,因为 //j+1e6 更换成2e6其实也可以 ,考虑这样一组数据, // 假设1e6 换成100 当i是94的时候,(1,94)(94,188)这时候 //因为j代表的是右边界,所以区间话(94,188)超过了1e6所以跳出 //但是这个区间内的数也是应该计算的,所以要跑到2e6 { int fen = max(j-i+1,j-p); // 对于每个区间(j-i+1,j)找到他的分界点 vsum = ssum[j]-ssum[fen-1];//需要增加1的数的个数 nsum1 = num[j]-num[fen-1];//需要增加1的的数的总和 //j*vsum为这些数需要增加到的总和 nsum2 = num[fen-1]-num[j-i];//统计需要删除的个数 sum+= nsum2*x; sum+=(j*nsum1-vsum)*y;//统计本区间内需要增加的数值 } // cout<<sum<<endl; ans = min(ans,sum); } cout<<ans<<endl; } return 0; }
相关文章推荐
- Codeforces 432 Div. 2-D-Arpa and a list of numbers(枚举倍数求GCD)
- codeforces 851 #432 div2 C Five Dimensional Points
- Codeforces Round #432 (Div. 2) (Codeforces 850C) E. Arpa and a game with Mojtaba 博弈+状态压缩
- Codeforces - 277.5 (Div. 2)C - Given Length and Sum of Digits...(模拟 or dfs)
- CodeForces 839B - Game of the Rows | Codeforces Round #428 (Div. 2)
- codeforces-DIV2-A-Jzzhu and Children
- Codeforces Div. 2 #257-B. Jzzhu and Sequences
- 【Codeforces Round #402 (Div. 1)】Codeforces 778B Bitwise Formula
- Codeforces Round #257 (Div. 1) (Codeforces 449B)
- codeforces 259 div2 virtual Participation
- Codeforces 827D (Round #423 Div. 1) D. Best Edge Weight 树上倍增
- CodeForces 840A - Leha and Function | Codeforces Round #429 (Div. 1)
- CodeForces 840C - On the Bench | Codeforces Round #429 (Div. 1)
- codeforces 260 div2 A,B,C
- CodeForces 508D(Codeforces Round #288 (Div. 2))Tanya and Password
- Codeforces Round #209 (Div. 2) B && Codeforces 359 B(构造)
- 【CodeForces】CodeForces Round #466 (Div. 2) 题解
- codeforces 208(div2) A+B+C+D
- Codeforces Codeforces Round #432 (Div. 2 D ) Arpa and a list of numbers
- Codeforces Round #432 (Div. 2, based on IndiaHacks Final Round 2017)C. Five Dimensional Points