首页 > 其他分享 >P2714 循环不变式的基础应用

P2714 循环不变式的基础应用

时间:2023-06-08 20:22:57浏览次数:51  
标签:int sum 不变式 循环 答案 P2714 我们

你听说过循环不变式吗?不妨来品鉴一下吧:WeLikeStudying 大佬的博客:循环不变式

而这篇文章,只是对大佬博客的小小注解,外加一点实际应用。


  • 我们可以把循环不变式理解成一组条件。在每次循环中,我们保证这组条件均为真。而最后循环就可以得出我们想要的结果。

  • 如果思考本质,这实际上可以一种数学归纳法。我们保证了循环任何时候都满足条件,只需要验证满足了这组条件就能求出答案。

  • 满足的条件可以是显示在代码中的,也可以是隐藏起来的。

举个例子,斐波拉契数列中,我们创造两个变量 \(a,b\),且保证:

\[a = fib(i), b = fib(i + 1) \]

那么就可以求出答案。

  • 我们可以发现,选择一组好实现的条件,是化繁为简的关键。

现在我们看到这道题:

  • 首先这道题和 \(gcd\) 有关,再看到数据范围,这意味着我们的复杂度只要和每个数的倍数有关,就能通过此题。

  • 最简单的条件是创造数组 \(f_i\),且 \(f(i)=ans(i)\)。其中 \(ans(i)\) 就是 \(gcd(a,b,c,d) = i\) 的答案。但是我们发现这不好实现。

  • 考虑扩大条件。我们不能求出恰好的答案,但是我们可以求出至少的答案。具体地,我们定义 \(g_i\) 为 \(gcd(a,b,c,d) | i\) 的个数。我们枚举每个数的倍数,可以在 \(n \ln n\) 的时间内求出来。

  • 最后,我们寻找这两者的关系。要得到恰好为 \(i\) 的答案,就要把所有比 \(i\) 大的答案都从 \(g_i\) 剔除出去。因此,我们得出 \(f_i = g_i - \sum_{j | i} f_j\)。

  • 注意这个式子去除了一次 \(f_i\)。但是由于此时 \(f_i\) 没有求出,应该为 \(0\),所以没有影响。

总结一下,在程序中,我们只要满足下面的条件,那么 \(f(1)\) 就是答案(设 \(i\) 在序列中出现了 \(num_i\) 次)。

\[g_i = \sum_{j | i} num_j \]

\[f_i = g_i - \sum_{j | i} f_j \]

下面是代码:

#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1e4 + 5;

int n;
int a[N];

long long ton[N], f[N], g[N];

void solve() {
  for (int i = 1; i <= n; ++i) cin >> a[i];

  int mxa = 0;
  for (int i = 1; i <= n; ++i) mxa = max(mxa, a[i]);
  for (int i = 1; i <= mxa; ++i) f[i] = g[i] = ton[i] = 0;
  for (int i = 1; i <= n; ++i) ++ton[a[i]];

  for (int i = mxa; i >= 1; --i) {
    long long sum_g = 0, sum_f = 0;
    for (int j = 1; i * j <= mxa; ++j) {
      sum_g += ton[i * j];
      sum_f += f[i * j];
    }
    g[i] = (sum_g * (sum_g - 1) * (sum_g - 2) * (sum_g - 3)) / (4 * 3 * 2 * 1);
    f[i] = max(1LL * 0, g[i] - sum_f);
  }

  cout << f[1] << endl;
}

signed main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);

  while (cin >> n) solve();

  return 0;
}

标签:int,sum,不变式,循环,答案,P2714,我们
From: https://www.cnblogs.com/closureshop/p/solution-P2714.html

相关文章

  • JS引擎中的线程,事件循环,上下文
     线程浏览器中有哪些进程呢?1.浏览器进程:浏览器的主进程,负责浏览器的界面界面显示,与用户交互,网址栏输入、前进、后退,以及页面的创建和销毁。2.渲染进程(浏览器内核):默认一个tab页面一个渲染进程,主要的作用为页面渲染,脚本执行,事件处理等。3.GPU进程:用于3D绘制等,将开启了3D绘制......
  • 【python基础】循环语句-break关键字
    1.break关键字break关键字,其作用是在循环中的代码块遇到此关键字,立刻跳出整个循环,执行循环外的下一条语句。其在while和for循环中的作用示意图如下:1.1break在while循环中的使用1.1.1不加else语句比如我们通过键盘输入单词,输出刚才的单词,编写程序如下所示:我们发现当我们输......
  • 【python基础】循环语句-for循环
    1.初始for循环for循环可以遍历任何可迭代对象,如一个列表或者一个字符串。这里可迭代对象的概念我们后期介绍,先知道这个名词就好了。其语法格式之一:比如我们遍历学员名单,编写程序如下所示:for循环如果放在生产生活中的话,也类似于循环处理,但较while循环有区别,其区别就在于条件......
  • Matlab用深度学习循环神经网络RNN长短期记忆LSTM进行波形时间序列数据预测|附代码数据
    全文链接:http://tecdat.cn/?p=27279最近我们被客户要求撰写关于深度学习循环神经网络RNN的研究报告,包括一些图形和统计输出。此示例说明如何使用长短期记忆(LSTM)网络预测时间序列LSTM神经网络架构和原理及其在Python中的预测应用LSTM网络是一种循环神经网络(RNN),它通过循......
  • Python在循环中修改遍历的字符串
    举例展示Python在循环中修改遍历的字符串,将不会影响循环的遍历顺序和执行轮数astr="abcaef"bstr="bcef"foriinastr:ifinotinbstr:astr=astr.replace(i,'')print(i)如上示例代码中,当i='a'时,bstr中没有'a',输出'a'......
  • 循环中调用异步接口获取数据
      //查询人员列表  asyncgetPersonList(){   const_this=this;   constdata=awaitgetPersonList(this.formSearch);   console.log("data",data);   varpromiseList=[];   data.forEach((element,inds)=>{   ......
  • 列表循环-强调v-for循环中key值的注意点
    key的注意事项key的值只能是字符串或数字类型key的值必须具有唯一性(即:key的值不能重复)建议把数据项id属性的值作为key的值(因为id属性的值具有唯一性)使用index的值当作key的值没有任何意义(因为index的值不具有唯一性)建议使用v-for指令时一定要指定key的值(即提升性能、又防止......
  • 逍遥自在学C语言 | break-循环的中断与跳转
    前言在C语言中,break语句是一种控制流语句,它用于终止当前所在的循环结构(for、while、do-while)或者switch语句,从而跳出循环或者结束switch语句的执行。一、人物简介第一位闪亮登场,有请今后会一直教我们C语言的老师——自在。第二位上场的是和我们一起学习的小白程序猿—......
  • 不能在foreach 循环中添加或删除元素
    迭代器在遍历map的时候,会先拿到modCount存起来然后遍历,在遍历的时候会判断当前modCount的值与我第一次进来存的值是否一样,不一样就报错如果在循环中添加或删除元素,是直接调用集合的add,remove方法【导致了modCount增加或减少】,但这些方法不会修改迭代实例中的expectedModCount,导......
  • 流程控制之for循环
    目录一、语法二、for+break三、for+continue四、for循环嵌套五、for+else六、for循环实现loading一、语法for循环可以用于对序列(如字符串、列表或元组)进行迭代操作,其基本语法如下:复制代码for变量in序列:循环体代码其中变量是在每次迭代时,序列中的下一个值,并且该......