【链接】 我是链接,点我呀:)

【题意】

在这里输入题意

【题解】

如果我们对某一个位置i操作两次的话。
显然结果就和操作一次一样。
因为第一次操作过后1..i这些数字就变成是互质的了。
gcd为1.那么除过之后没有影响的。

然后。就是要明白

那个f(x)函数的意义。其实就是问你x质因数分解之后,其中好的质数和坏的质数的差是多少。

也即有多少个好因数,多少个坏因数。

(以下的gcd(i)都指的是a[1..i]这些数字的gcd

然后考虑我们在第i个位置进行了一次操作。

显然他会对后面的数字造成影响。

比如在第i个位置进行了一次操作。

那么我们在第i+1个位置进行操作的时候,就会发现gcd(i+1)此时已经不是之前的数字。会变成1.

这样我们可能就会漏解。

因为gcd(i)>=gcd(i+1)

我们可能除得太多了。

使得我们下一次不能除少一点了。

但是如果我们倒过来做的话,就会不一样。

比如我们先在i进行了一次操作。

之后再到i-1进行一次操作的话。

gcd(i-1)不一定就等于1;

因为原先gcd(i-1)>=gcd(i)

所以在i进行的操作的时候。

我们下一次到某个小于i的位置的时候,

只需记录一下上一次已经除掉了多少。

这次再加的时候去掉上次的影响就好了。

但是假设我们在i,j,k(i<j<k)这3个位置都进行了操作。

我们只需要记录gcd(j)就好。

因为gcd(k)肯定包含在gcd(j)中了。

然后在j位置的影响再累加一下就是gcd(k)了;

然后在i位置的影响就是gcd(i)/gcd(k)了;

也就是说,我们在算gcd(i)的好素数和坏素数差的时候,只需要把它当成gcd(i)/gcd(k)算就好了。

(前提是之前已经选过k这个位置了。

根据上面的分析我们可以用动态规划来解决这个问题了。

需要维护两个量,1个是当前的位置,另外就是上一次进行操作的位置。

每个位置i有两种选择:

1.不进行操作,则上一次进行操作的位置不变。

2.进行一次操作,则上一次进行操作的位置变成i.

设f(x)表示x的美丽值。

dp[i][j]表示前i个位置,上一次选择的位置是j的最大美丽值。



\(dp[i][i] = max(dp[i][i],dp[i+1][j]+(gcd[j]-gcd[i])*i; 第i个位置进行一次操作\)

\(dp[i][j] = max(dp[i][j],dp[i+1][j]);第i个位置不进行一次操作\)

初值dp[n+1][n+1]等于\(∑f(a[i])\)

(即不进行任何操作

(这里n+1就表示之前没有进行任何一次操作的情况。

(根据上面的讨论,不难想到这个dp应该倒序做即i倒序。但是j的话随意吧。

最后取max(dp[i][j])就是答案了。

【代码】

#include <bits/stdc++.h>
#define ll long long
using namespace std; const int N = 5e3; int n, m, a[N + 10],_gcd[N+10];
int dp[N + 10][N + 10];//前i个数字,上一次操作的位置在j的最大美丽值。
set<int> myset;
map<int, int> dic; int gcd(int x, int y) {
if (y == 0)
return x;
else
return gcd(y, x%y);
} int f(int x) {
if (x <= 1) return dic[x] = 0;
if (dic.find(x) != dic.end()) return dic[x];
int temp = x,point = 0;
for (int i = 2; i*i <= temp; i++)
if (temp%i == 0) {
int flag = 0;
if (myset.find(i) != myset.end()) {//找到了
flag = -1;
}
else {
flag = 1;
}
while (temp%i == 0) {
temp /= i;
point += flag;
}
} if (temp > 1) {
if (myset.find(temp) != myset.end())
point--;
else
point++;
}
return dic[x] = point;
} int main() {
#ifdef LOCAL_DEFINE
freopen("rush_in.txt", "r", stdin);
#endif
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i];
_gcd[1] = a[1];
for (int i=2; i <= n; i++) _gcd[i] = gcd(_gcd[i - 1], a[i]); for (int i = 1; i <= m; i++) {
int x;
cin >> x;
myset.insert(x);
} memset(dp, -0x3f3f3f3f, sizeof dp); dp[n + 1][n + 1] = 0;
for (int i = 1; i <= n; i++) dp[n+1][n + 1] += f(a[i]);
for (int i = n;i >= 1;i--)
for (int j = n + 1; j > i; j--) {
//在i这个位置放一个
dp[i][i] = max(dp[i][i], dp[i + 1][j] +f(_gcd[j])*i- f(_gcd[i]) * i);
//i这个位置不放
dp[i][j] = max(dp[i][j], dp[i + 1][j]);
} int ans = dp[n + 1][n + 1];
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
ans = max(ans, dp[i][j]);
cout << ans << endl;
return 0;
}

【Henu ACM Round#17 F】Upgrading Array的更多相关文章

  1. 【Henu ACM Round#16 F】Om Nom and Necklace

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] KMP算法可以把"i前缀"pre[i] 分成ssssst的形式 这里t是s的前缀. 然后s其实就是pre[i]中 ...

  2. 【Henu ACM Round#17 E】Tree Construction

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 做这题之前先要知道二叉排序树的一个性质. 就是它的中序遍历的结果就是这个数组升序排序. (且每个节点的左边的节点都是比这个节点的值小 ...

  3. 【Henu ACM Round#17 C】Kitahara Haruki's Gift

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 判断sum/2这个价值能不能得到就可以了. 则就是一个01背包模型了. 判断某个价值能否得到. f[j]表示价值j能否得到. f[0 ...

  4. 【Henu ACM Round#17 B】USB Flash Drives

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 排序,逆序.贪心选较大的就好. [代码] #include <bits/stdc++.h> #define ll lon ...

  5. 【Henu ACM Round #13 F】Fibonacci-ish

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 枚举序列的头两个数字是什么 O(N^2) 然后头两个数字确定之后. f[3],f[4]..就确定了 只需查看f[3],f[4]..是 ...

  6. 【Henu ACM Round#15 F】Arthur and Questions

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] a1+a2+...+ak<a2+a3+...ak+1 ->a1<ak+1 a2+a3+...+ak+1<a3 ...

  7. 【Henu ACM Round#18 F】Arthur and Walls

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 考虑,为什么一个连通块里面的空格没有变成一个矩形? 如果不是形成矩形的话. 肯定是因为某个2x2的单张方形里面. 只有一个角是墙.其 ...

  8. 【Henu ACM Round#20 F】 Arthur and Brackets

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 所给的li,ri是左括号从左到右的顺序给的. (且注意长度是2*n 现在我们先把第一个左括号放在第1个位置. 然后考虑第二个位置. ...

  9. 【Henu ACM Round#19 F】Dispute

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 这一题和这一题很像 (链接 ) 会发现如果a[i]!=b[i]那么就按下i就好了. 然后改变和他相邻的点. 此后a[i]再也不可能和 ...

随机推荐

  1. 初识Git(三)

    这次要记录一下对branch,merge的学习. 与先前一样创建一个pro文件夹,initi该文件夹,在该文件夹中新建一个空的MainCode.txt,然后add文本文件并且commit. 接下来我们 ...

  2. pyftpdlib 搭建ftp环境

    环境搭建: pythonwindows/linuxpip install pyftpdlib (安装失败请到这里下载:https://pypi.python.org/pypi/pyftpdlib/)一 ...

  3. NOIp2018模拟赛四十三

    有了昨天的经验,不慌,开题先看source ******** 再看看题,看到C题标题: ******** 有毒... B题的“显然”50分结论推了我一个小时,然后就弃疗了... 成绩:0+50+5=5 ...

  4. (WC2018模拟十二)【FJOI2016集训Day7T2】点对游戏

    题解: 还好...看懂题目就好做了.(Orzdyh) 首先选择的点是等概率随机的,也就是说每种选择结果的概率都是一样的,所以选择一个点的时候已经选择的点不会有影响,那么就可以直接算出点对个数再求总体的 ...

  5. layui Layui-Select多选的使用和注意事项

    1.最近买了layadmin的后台框架,使用Layui-Select总结如下 A.配置:我采用的全局引入配置的方式 赋值(选中状态)

  6. python基础4(小数据池,编码,深浅拷贝)

    1.==与is == 比较值是否相等 is比较内存地址是否相同 2.小数据池 为了节省内存,当数据在一个范围里的时候,两个值相同的变量指向的是小数据池里的同一个地址 数字范围:-5 ~ 256 num ...

  7. 国庆 day 7 上午

    思路:模拟,set记录一下. #include<set> #include<cstdio> #include<cstring> #include<iostre ...

  8. Qt之图形(绘制漂亮的圆弧)

    简述 综合前面对二维绘图的介绍,想必我们对一些基本绘图有了深入的了解,下面我们来实现一些漂亮的图形绘制. 简述 圆形 效果 源码 弧形 效果 源码 文本 效果 源码 旋转 效果 源码 圆形 经常地,我 ...

  9. windows 下面的grep awk 命令

    windows 下面的grep awk 命令 grep 学习了:http://blog.csdn.net/chengfans/article/details/53784936 awk学习了:http: ...

  10. 4.有关日期格式属性改动常识,v$nls_parameters,between and,查询指定部门的员工信息,in和null,like模糊查询,order by后面能够跟:列名、表达式、别名、序号

     1 有关日期格式属性改动常识 NLS_DATE_FORMAT           DD-MON-RR select sysdate from dual; NLS_CURRENCY         ...