AIM Tech Round (Div. 2) D. Array GCD(dp)
来源:互联网 发布:linux 局域网传文件 编辑:程序博客网 时间:2024/06/05 20:24
题意:
给定N≤106的一个序列,现有2种操作
1.删除一个长度为0≤M<N的连续子序列,删除代价为M∗A
2.更改0≤K≤N个元素,使得它们+1或者−1,更改代价为K∗B
2种操作至多各做一次,使得产生的序列的gcd>1
求最小代价
分析:
由于删除的是连续序列且不能删除完,那么显然a1,an会至少留下一个
由于gcd很多有109个,但是我们发现最终的gcd是整除a1,a1±1或者an,an±1的素因子的
素因子就很少了,是log级的,接下来就可以暴力dp了
f[prime][i][3]:=1∼i个数,gcd能整除prime,删除的连续子序列→0/没有开始,1/删除中,2/删除结束,的最小代价
然后暴力转移即可
ans=min{f[prime][N][0],f[prime][N][2]}
时间复杂度为O(nlog109)
注意虽然dp会把整个序列都删掉,但是思考发现这个不会成为最优解,因为我们会有至少留下一个数的更优解
代码:
//// Created by TaoSama on 2016-02-05// Copyright (c) 2016 TaoSama. All rights reserved.//#pragma comment(linker, "/STACK:1024000000,1024000000")#include <algorithm>#include <cctype>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <iomanip>#include <iostream>#include <map>#include <queue>#include <string>#include <set>#include <vector>using namespace std;#define pr(x) cout << #x << " = " << x << " "#define prln(x) cout << #x << " = " << x << endlconst int N = 1e6 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;int n, A, B;int a[N];long long f[2][3]; //0->removed array, not started, 1->removing, 2->finishedinline void getMin(long long &x, long long y) { if(x > y) x = y;}int getCost(int i, int p) { if(a[i] % p == 0) return 0; else if((a[i] + 1) % p == 0 || (a[i] - 1) % p == 0) return B; return INF;}void see(int i, int s) { for(int j = 0; j < 3; ++j) printf("f[%d][%d]=%I64d\n", i, j, f[s][j]);}long long gao(int p) { int s = 0; memset(f[s], 0, sizeof f[s]); for(int i = 1; i <= n; ++i) { memset(f[!s], 0x3f, sizeof f[!s]); int cost = getCost(i, p); if(cost != INF) { getMin(f[!s][0], f[s][0] + cost); getMin(f[!s][2], f[s][2] + cost); } getMin(f[!s][1], f[s][0] + A); //start removing getMin(f[!s][1], f[s][1] + A); //removing getMin(f[!s][2], f[s][0] + A); //finish right away getMin(f[!s][2], f[s][1] + A); //finish removing s = !s;// if(p == 2) see(i, s); } return min(f[s][0], f[s][2]);}int main() {#ifdef LOCAL freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);#endif ios_base::sync_with_stdio(0); while(scanf("%d%d%d", &n, &A, &B) == 3) { for(int i = 1; i <= n; ++i) scanf("%d", a + i); int leave[] = {a[1], a[n]}; long long ans = 1e18; for(int i = 0; i < 2; ++i) { for(int d = -1; d <= 1; ++d) { int x = leave[i] + d; for(int j = 2; j * j <= x; ++j) { if(x % j == 0) { ans = min(ans, gao(j)); while(x % j == 0) x /= j; } } if(x > 1) ans = min(ans, gao(x)); } } printf("%I64d\n", ans); // return 0; } return 0;}
当然还可以通过prefix,suffix来做这个题
g[i]:=保留1∼i的最小代价 | 保留i∼n的最小代价
f[i]:=1∼i个数前缀满足要求的最小代价
暴力转移即可
代码:
//// Created by TaoSama on 2016-02-05// Copyright (c) 2016 TaoSama. All rights reserved.//#pragma comment(linker, "/STACK:1024000000,1024000000")#include <algorithm>#include <cctype>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <iomanip>#include <iostream>#include <map>#include <queue>#include <string>#include <set>#include <vector>using namespace std;#define pr(x) cout << #x << " = " << x << " "#define prln(x) cout << #x << " = " << x << endlconst int N = 1e6 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;int n, A, B;int a[N];long long f[N], g[N];long long gao(int p) { int pos = -1; for(int i = 1; i <= n; ++i) { if(a[i] % p == 0) g[i] = g[i - 1]; else if((a[i] + 1) % p == 0 || (a[i] - 1) % p == 0) g[i] = g[i - 1] + B; else break; pos = i; } for(int i = 1; i <= n; ++i) { f[i] = f[i - 1] + A; if(i <= pos) f[i] = min(f[i], g[i]); } g[n + 1] = 0; long long ret = f[n]; for(int i = n; i; --i) { if(a[i] % p == 0) g[i] = g[i + 1]; else if((a[i] + 1) % p == 0 || (a[i] - 1) % p == 0) g[i] = g[i + 1] + B; else break; ret = min(ret, f[i - 1] + g[i]); } return ret;}int main() {#ifdef LOCAL freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);#endif ios_base::sync_with_stdio(0); while(scanf("%d%d%d", &n, &A, &B) == 3) { for(int i = 1; i <= n; ++i) scanf("%d", a + i); int leave[] = {a[1], a[n]}; long long ans = 1e18; for(int i = 0; i < 2; ++i) { for(int d = -1; d <= 1; ++d) { int x = leave[i] + d; for(int j = 2; j * j <= x; ++j) { if(x % j == 0) { ans = min(ans, gao(j)); while(x % j == 0) x /= j; } } if(x > 1) ans = min(ans, gao(x)); } } printf("%I64d\n", ans); } return 0;}
0 0
- AIM Tech Round (Div. 2) D. Array GCD(dp)
- AIM Tech Round (Div. 2) D. Array GCD(dp,two pointers)
- 【DP】AIM Tech Round (Div. 2) D
- AIM Tech Round (Div. 1) B. Array GCD(数论+dp)
- codeforces AIM Tech Round 3 (Div. 2) (A~D)
- cf#AIM Tech D. Array GCD (数学+枚举)
- CodeForces AIM Tech Round 3 (Div. 2) D
- Codeforces AIM Tech Round 3 (Div. 2)(A-D 未完)
- AIM Tech Round 4 (Div. 2) D. Interactive LowerBound
- AIM Tech Round 4 (Div. 2) D. Interactive LowerBound
- AIM Tech Round 3 (Div. 2) -- D. Recover the String (思路题目--构造字符串)
- AIM Tech Round 3 (Div. 2) -- D. Recover the String (构造字符串)
- AIM Tech Round 3 (Div. 2) D. Recover the String (构造)
- AIM Tech Round 3 (Div. 2) E. Centroids (树形dp)
- AIM Tech Round 3 (Div. 2) E. Centroids (树形dp) ★ ★ ★
- AIM Tech Round (Div. 2)-A. Save Luke(数学题)
- AIM Tech Round (Div. 2)(A)数学
- AIM Tech Round (Div. 2)(B)模拟
- shrio 权限管理filterChainDefinitions过滤器配置
- JQuery3(map,each,trim方法)
- jQuery.extend函数详解--
- poj2001 Shortest Prefixes (trie树)
- 并查集
- AIM Tech Round (Div. 2) D. Array GCD(dp)
- POJ3694 Network(边双连通+LCA)
- xib自定义非等高的cell
- 数据结构基础之双向链表(约瑟夫问题)
- 简易图解移轴镜头 (Tilt-Shift Lens) 原理 简易图解移轴镜头 (Tilt-Shift Lens) 原理
- Codeforces 577A Multiplication Table
- 界面元查询参数构件
- 穷人的“移轴”,普通镜头秒变“移轴”镜头 - 新增倾斜实拍
- 安卓开发——invalidate()自动清屏和屏幕刷新