Codeforces 623B Array GCD(枚举情况+dp)
2016-09-13 21:17
302 查看
给你一个数列,你能删除其中的连续的一段,花费是删除的数字个数∗a
你也可以把某些数字+1或者−1,对于每个数字只能做一次,花费是b
然后让你花费最少,让剩下的数列gcd不是1
首先要发现,因为不能完全删除整个数列,所以要么左端点肯定存在,要么右端点肯定存在
并且gcd只要不等于1,所以可以枚举两个端点+1,−1,+0的情况下的所有素因子
然后对于每个素因子,去考察这个数列的每一项,枚举前后缀的最小花费和
如果直接和素因子gcd!=1,那么显然不变换,如果不行,就+1,−1,如果还不行就break
然后考虑左边全删除,右边全删除,还有是删除中间段
左右全删很简单,删除中间其实就是min(p1[i]−i∗a+j∗a+p2[j])
只要扫j的时候,记录前面最小的p1[i]−i∗a就行了
代码:
你也可以把某些数字+1或者−1,对于每个数字只能做一次,花费是b
然后让你花费最少,让剩下的数列gcd不是1
首先要发现,因为不能完全删除整个数列,所以要么左端点肯定存在,要么右端点肯定存在
并且gcd只要不等于1,所以可以枚举两个端点+1,−1,+0的情况下的所有素因子
然后对于每个素因子,去考察这个数列的每一项,枚举前后缀的最小花费和
如果直接和素因子gcd!=1,那么显然不变换,如果不行,就+1,−1,如果还不行就break
然后考虑左边全删除,右边全删除,还有是删除中间段
左右全删很简单,删除中间其实就是min(p1[i]−i∗a+j∗a+p2[j])
只要扫j的时候,记录前面最小的p1[i]−i∗a就行了
代码:
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm> #pragma comment(linker,"/STACK:102400000,102400000") using namespace std; #define MAX 1000005 #define MAXN 1000005 #define maxnode 15 #define sigma_size 30 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lrt rt<<1 #define rrt rt<<1|1 #define middle int m=(r+l)>>1 #define LL long long #define ull unsigned long long #define mem(x,v) memset(x,v,sizeof(x)) #define lowbit(x) (x&-x) #define pii pair<int,int> #define bits(a) __builtin_popcount(a) #define mk make_pair #define limit 10000 //const int prime = 999983; const int INF = 0x3f3f3f3f; const LL INFF = 0x3f3f; const double pi = acos(-1.0); const double inf = 1e18; const double eps = 1e-8; const LL mod = 1e9+7; const ull mx = 133333331; /*****************************************************/ inline void RI(int &x) { char c; while((c=getchar())<'0' || c>'9'); x=c-'0'; while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; } /*****************************************************/ int a[MAX]; vector<int> v; int n,A,B; LL p1[MAX],p2[MAX]; void check(int t){ for(int i=2;i*i<=t;i++){ if(t%i==0){ while(t%i==0) t/=i; v.push_back(i); } } if(t>1) v.push_back(t); } int gcd(int a,int b){ if(!b) return a; return gcd(b,a%b); } LL cal(int t){ if(t<=1) return 1e18; for(int i=0;i<=n+1;i++) p1[i]=p2[i]=1e18; p1[0]=p2[n+1]=0; for(int i=1;i<=n;i++){ if(gcd(t,a[i])>1) p1[i]=p1[i-1]; else if(gcd(t,a[i]+1)>1||gcd(t,a[i]-1)>1) p1[i]=(LL)B+p1[i-1]; else break; } for(int i=n;i>0;i--){ if(gcd(t,a[i])>1) p2[i]=p2[i+1]; else if(gcd(t,a[i]+1)>1||gcd(t,a[i]-1)>1) p2[i]=(LL)B+p2[i+1]; else break; } LL ans=1e18; LL tmp=0; for(int i=1;i<=n;i++){ ans=min(ans,p2[i]+(LL)A*(i-1)+tmp); tmp=min(tmp,p1[i]-(LL)A*i); } for(int i=n;i>0;i--) ans=min(ans,p1[i]+(LL)A*(n-i)); return ans; } int main(){ //freopen("in.out","r",stdin); while(~scanf("%d%d%d",&n,&A,&B)){ for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=-1;i<=1;i++) { check(a[1]+i); check(a +i); } sort(v.begin(),v.end()); v.erase(unique(v.begin(),v.end()),v.end());//vector的去重 LL ans=1e18; for(int i=0;i<v.size();i++) ans=min(ans,cal(v[i])); printf("%I64d\n",ans); } return 0; }
相关文章推荐
- HTML FileReader
- redis三种启动设置
- Java的多线程-2
- leetcode之92. Reverse Linked List II(C++读错题版本,交换一个链表中指定的两个位置上的元素)
- javascript在html中的加载顺序
- C# 托管资源和非托管资源
- (C语言)自制贪吃蛇
- HTTPS协议
- hh
- android两种日志获取log4j
- LeetCodeOJ——10. Regular Expression Matching
- Linux下SSH免密码登录
- .net面试题
- HTML学习小结之HTML标签
- 一些linux 与磁盘相关命令
- 混淆必知必会
- LibGdx文档译读(十) Preferences接口
- codevs1743
- 全排列问题
- Jquery easyui教程