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

【题意】

在这里输入题意

【题解】

如果我们对某一个位置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])就是答案了。

【代码】

  1. #include <bits/stdc++.h>
  2. #define ll long long
  3. using namespace std;
  4. const int N = 5e3;
  5. int n, m, a[N + 10],_gcd[N+10];
  6. int dp[N + 10][N + 10];//前i个数字,上一次操作的位置在j的最大美丽值。
  7. set<int> myset;
  8. map<int, int> dic;
  9. int gcd(int x, int y) {
  10. if (y == 0)
  11. return x;
  12. else
  13. return gcd(y, x%y);
  14. }
  15. int f(int x) {
  16. if (x <= 1) return dic[x] = 0;
  17. if (dic.find(x) != dic.end()) return dic[x];
  18. int temp = x,point = 0;
  19. for (int i = 2; i*i <= temp; i++)
  20. if (temp%i == 0) {
  21. int flag = 0;
  22. if (myset.find(i) != myset.end()) {//找到了
  23. flag = -1;
  24. }
  25. else {
  26. flag = 1;
  27. }
  28. while (temp%i == 0) {
  29. temp /= i;
  30. point += flag;
  31. }
  32. }
  33. if (temp > 1) {
  34. if (myset.find(temp) != myset.end())
  35. point--;
  36. else
  37. point++;
  38. }
  39. return dic[x] = point;
  40. }
  41. int main() {
  42. #ifdef LOCAL_DEFINE
  43. freopen("rush_in.txt", "r", stdin);
  44. #endif
  45. ios::sync_with_stdio(0), cin.tie(0);
  46. cin >> n >> m;
  47. for (int i = 1; i <= n; i++) cin >> a[i];
  48. _gcd[1] = a[1];
  49. for (int i=2; i <= n; i++) _gcd[i] = gcd(_gcd[i - 1], a[i]);
  50. for (int i = 1; i <= m; i++) {
  51. int x;
  52. cin >> x;
  53. myset.insert(x);
  54. }
  55. memset(dp, -0x3f3f3f3f, sizeof dp);
  56. dp[n + 1][n + 1] = 0;
  57. for (int i = 1; i <= n; i++) dp[n+1][n + 1] += f(a[i]);
  58. for (int i = n;i >= 1;i--)
  59. for (int j = n + 1; j > i; j--) {
  60. //在i这个位置放一个
  61. dp[i][i] = max(dp[i][i], dp[i + 1][j] +f(_gcd[j])*i- f(_gcd[i]) * i);
  62. //i这个位置不放
  63. dp[i][j] = max(dp[i][j], dp[i + 1][j]);
  64. }
  65. int ans = dp[n + 1][n + 1];
  66. for (int i = 1; i <= n; i++)
  67. for (int j = i; j <= n; j++)
  68. ans = max(ans, dp[i][j]);
  69. cout << ans << endl;
  70. return 0;
  71. }

【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. 51nod 1021 石子归并 (动态规划 简单代码)

    题目: 思路:动态规划,递推式子 dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]);     dp[i][j]表示 ...

  2. Linux 安装软件的几种方式

    目录 几种安装方式 源代码编译安装 借助软件包管理器安装 二进制格式安装 总结 参考 几种安装方式 源代码编译安装 源代码包的安装一般为下载软件源代码,然后编译安装.常见的 C 程序软件的安装步骤是 ...

  3. HDU 1704 Rank【传递闭包】

    解题思路:给出n个选手,m场比赛,问不能判断胜负的询问最多有多少种 用传递闭包即可 但是如果直接用3重循环会超时 在判断d[i][j]=d[i][k]||d[k][j]是否连通的时候 可以加一个if语 ...

  4. div控制最小高度又自适高度

    div控制最小高度又自适高度我们在用div布局的时候经常会遇到这样的一种情况:我们需要设置一个div的高度,当里面的东西超过这个高度时,让这个容器自动被撑开,也就是自适应高度.当里面的信息很少时候,我 ...

  5. IIFE 萌新学习笔记

    立即执行函数表达式(IIFE) IIFE:Immediately-Invoked Function Expression(立即执行函数表达式) 一 常用写法: //经常使用的写法(function() ...

  6. [ZJOI2007]捉迷藏 (点分树+堆*3)

    点分树一点都不会啊(还是太菜了) 点分树就是我们点分治构成的新树.满足深度很小. 然后我们就可以在上面瞎维护东西了. 三个大根堆: \(C[u]\)里装的是点分树中u的子树所有点到点分树中u的父亲的距 ...

  7. SFTP使用key文件登录

    命令: sftp -oPort= -oIdentityFile=/root/.ssh/user.priv user@39.39.100.100 命令选项: -o ssh_option Can be u ...

  8. Redis散杂记

    Redis是一款很火的KV模式的内存数据库,与众不同的特点: 1.数据存储在内存 内存的读取速度仅次于CPU的寄存器.各等级缓存,“英雄”自动敏捷属性,特点就是快.高效.因此不需要类似存储磁盘的数据库 ...

  9. 紫书 习题8-19 UVa 1312 (枚举技巧)

    这道题参考了https://www.cnblogs.com/20143605--pcx/p/4889518.html 这道题就是枚举矩形的宽, 然后从宽再来枚举高. 具体是这样的, 先把所有点的高度已 ...

  10. swift入门-实现简单的登录界面

    // // AppDelegate.swift // UIWindow import UIKit @UIApplicationMain class AppDelegate: UIResponder, ...