首页 > 其他分享 >CF1715C 题解

CF1715C 题解

时间:2022-08-27 13:22:52浏览次数:87  
标签:return int 题解 LL long 贡献 CF1715C op

前言

题目传送门!

更好的阅读体验?

简单的数学题。

思路

每次只变一个数,因此考虑在短时间内计算:每个位置的数产生的贡献。

容易发现以下的条件:

  • 不管 \(a_i\) 是什么,当它作为一个子串的首项时,块数一定会加一。共有 \((n - i + 1)\) 个串的首项是 \(a_i\)。
  • 如果 \(a_i \ne a_{i-1}\),所有包含 \(a_i\) 与 \(a_{i+1}\) 的子串,块数都加一。乘法原理,头有 \((i - 1)\) 个位置可以选(\(0\) 到 \(i - 1\)),尾有 \((n - i + 1)\) 个位置可以选(\(i\) 到 \(n\)),共 \((i - 1) \times (n - i + 1)\)。

那么,我们就可以知道 \(a_{i - 1}\) 与 \(a_i\) 间产生的贡献是多少。

typedef long long LL;
LL calc(int i) //统计 a[i-1]与a[i]间产生的贡献
{
	LL k = n - i + 1; //以 a[i] 为头的所有子串,不管a[i-1]与a[i]相不相同,都要计算贡献。 
	if (a[i-1] == a[i]) return k;
	return 1ll * (i - 1) * (n - i + 1) + k; //不同才会产生贡献
}

然后,我们可以计算:原本的 \(a\) 数组有多少贡献。这非常简单。

LL sum = 0;
for (int i = 1; i <= n; i++) a[i] = read();
for (int i = 1; i <= n; i++) sum += calc(i);

那么,怎样在短时间内计算 \(a_i\) 改变后的值呢?只需要:

  1. 减去 \(a_{i-1}\) 与 \(a_i\) 产生的贡献,减去 \(a_i\) 与 \(a_{i + 1}\) 产生的贡献。因为它们过一会会变。
  2. 更改 \(a_i\)。
  3. 重新加上 \(a_{i-1}\) 与 \(a_i\) 产生的贡献,以及加上 \(a_i\) 与 \(a_{i + 1}\) 产生的贡献。

然后再输出结果即可。

完整代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#define space putchar(' ')
#define endl putchar('\n')
using namespace std;
typedef long long LL;
int read()
{
	char op = getchar(); int x = 0, f = 1;
	while (op < 48 || op > 57) {if (op == '-') f = -1; op = getchar();}
	while (48 <= op && op <= 57) x = (x << 1) + (x << 3) + (op ^ 48), op = getchar();
	return x * f;
}
void write(LL x)
{
	if (x < 0) putchar('-'), x = -x;
	if (x > 9) write(x / 10);
	putchar(x % 10 + 48);
}
int n, m, a[100005];
LL calc(int i) //统计 a[i-1]与a[i]间产生的贡献
{
	LL k = n - i + 1; //以 a[i] 为头的所有子串,不管a[i-1]与a[i]相不相同,都要计算贡献。 
	if (a[i-1] == a[i]) return k;
	return 1ll * (i - 1) * (n - i + 1) + k; //不同才会产生贡献
}
int main()
{
	n = read(), m = read();
	LL sum = 0;
	for (int i = 1; i <= n; i++) a[i] = read();
	for (int i = 1; i <= n; i++) sum += calc(i);
	while (m--)
	{
		int i = read(), k = read(); //a[i] = k
		sum -= calc(i), sum -= calc(i+1);
		a[i] = k;
		sum += calc(i), sum += calc(i+1);
		write(sum), endl;
	}
	return 0;
}

希望能帮助到大家!

首发:2022-08-25 12:22:47

标签:return,int,题解,LL,long,贡献,CF1715C,op
From: https://www.cnblogs.com/liangbowen/p/16630415.html

相关文章

  • CF1715B 题解
    前言题目传送门!更好的阅读体验?看起来挺难,其实一分钟就能想出来。思路首先考虑什么时候无解。由于\(k\times\left\lfloor\dfrac{a}{k}\right\rfloor\lea\le\le......
  • CF1715D 题解
    前言题目传送门!更好的阅读体验?感觉挺不错的一道图论转化题。(其实也和图论关系不大。)思路对于每个条件\(a_u\mida_v=x\),二进制拆掉\(x\)。如果\(x\)的二进制......
  • 「NOI2016」网格 题解
    「NOI2016」网格题解前言感谢zqm学长提供调代码服务!本文中,所有没有特殊说明的连通都是指四连通,相邻都是指上下左右相邻。题目大意有一个$n\timesm$的网格,上......
  • 【IAP Kit】应用内支付订单参数相关问题解析
    ​1、创建的订单orderId长度是多少?答:orderId的长度最大是255。 2、InappPurchaseDetails中orderId和payOrderId有什么区别呢?答:orderId和payOrderId这两者的区别如下:o......
  • 优先队列-多路归并系列题解
    373.查找和最小的K对数字问题描述给定两个以升序排列的整数数组nums1和nums2 , 以及一个整数k 。定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来......
  • 【题解】CF1007D Ants
    传送门题意:有\(m\)对链,每对链要选择一条,使得选择的链两两不交,求一组方案。题解:一眼看上去就是一个2-sat,考虑一种暴力的做法,枚举每一条边,覆盖这条边的链两两连边。......
  • 题解 UVA10791
    前言:数学符号约定:\(p\):任意一个质数\(n\)或\(m\):任意一个正整数\(a_i\):唯一分解时质数的指数\(A\):集合若无特殊说明,本篇题解的数学符号将会严格按照上......
  • 20220823 模拟赛题解
    T1文件压缩DecriptionlinkSolution可以根据\(S'\)和\(p\)求出第一个字符,然后把\(S'\)sort一遍后得到字符串\(T\),那么我们就可以求出每一个字符的前驱和后继,所......
  • LeetCode 链表的中间结点算法题解 All In One
    LeetCode链表的中间结点算法题解AllInOnejs/ts实现重排链表链表的中间结点原理图解//快慢指针functionmiddleNode(head:ListNode|null):ListNode|n......
  • k8s问题解决
    问题1:问题描述:k8s中Terminating状态pod不能删除[root@master~]#kubectlgetpods-nmsNAMEREADYSTATUSRESTARTSAGEportal-78......