首页 > 其他分享 >CF1398C Good Subarrays(写给我们萌新团体)

CF1398C Good Subarrays(写给我们萌新团体)

时间:2024-02-22 19:11:59浏览次数:35  
标签:这边 Good 遇到 Subarrays sum 个数 long CF1398C rep

Good Subarrays

传送门:

Good Subarrays - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路

暴力!!!!!

一如既往的暴力!!!

复杂度O(n^2) 数据n到1e5

TLE必定TLE

我们可以用一个桶来优化

实质上其实还是高中所学的排列组合思想

第一步:当然是前缀和了,这边讲给新手写一下,有点冗杂,是高手直接跳到文章结尾点个赞就可以走了

rep(i,1,n){
	sum[i]=sum[i-1]+a[i];
}
//有很多题解里可能出现rep等字样来代替for
//这边一般是用宏定义的方法,在本题中rep(i,1,n)表示范围为[1,n];
//就是sum[i-1]表示1~i-1的和,那么sum[i]=sum[i-1]+a[i]就表示前i-1的和加上第i个数就是1~i的和

ok!!!最基础的解决了

第二步:变形求解

sum[j]-sum[i]=j-i;
题目无非要求的就是这种情况的组成方案数
简单解析一下这是什么:
sum[j],sum[i]分别表示第前j个数的和和前i个数的和(这里令j>i,为了求i+1~j的和)
那么sum[j]-sum[i]就是i+1~j的和,j-i就是这个i+1~j这个区间有多少数
题目要求的不就是正好 区间i+1~j的和=区间里包含是数有几个
这边用i+1只是为了后面方便就计算
其实这变成i~j后面变成j-i+1也是一样的要有i=i+1这样的编程转换思想,要是不懂用x=i+1来套这里就不过多讲述

ok!?我们知道要求什么了
但是这样的条件是涉及到两个数的,涉及到两个数那只能是暴力判断符合条件然后一个一个加过去
我们这边就需要把他优化变成只涉及到当前数也就是一个数那边是不是可以优化到O(n)了

仔细一想变形成sum[j]-j=sum[i]-i是不是就至于i(说跟j相关也没关系跟上面所描述的变成思想是一回事)相关了

第三步:桶优化

这边用map来代替桶,为什么呢?
因为用数组可能越界
比例说我当前的数据为000000……
那是不是马上就可以知道前i个数之和减去i肯定小于0
用map虽然会稍微慢一点(因为map的查找是O(logn))但是这道题够用
基本够用的O(logn),因为O(logn)最多也才几十我感觉跟O(1)差不多的

开头我们说了这里和高中的排列组合有关系,就是在这
为了方便思考和方便写这边就不写sum[j]-j,sum[i]-i之类的我直接用第k个数表述(就是本小块中的第k个数就是表述sum[k]-k,第一个数就表示sum[1]-1,……以此类推,这句话有点扯淡,写到后面我发现好像这样跟繁琐了)
那么我们遇到一个从未遇到的情况那是不是没有别的情况与当前情况匹配,那么这时候当前方案数就是0
如果我们第二次遇到这种情况那么当前方案数就是1(因为符合了sum[j]-j=sum[i]-i也就是符合了sum[j]-sum[i]=j-i,这边i肯定不等于j的我就不加以赘述了)
那么以此类推我第三次遇到这种情况当前方案数就是2
……
但是有跟我一样的萌新可能就不懂了
第二次遇到肯定是好理解的,那么第三次遇到呢?
这边我们假设也不用假设后面遇到的k肯定是大于前面的
那么组成情况就有两种,第一次是跟第一次数遇到的组,第二次跟第二次遇到的数组
那是不是2种,
这边只需要考虑当前情况做j,然后把已有的情况做i(j是既定的,i是之前遇到的)

代码如下

	rep(i,1,n) {//与上述rep一样
		//a[i]=nums[i-1]-'0';
		//sum[i]=sum[i-1]+a[i];
		res+=m[sum[i]-i]++;这边其实求完m之后做一个0~n-1的等差数列也ok的意思一样的要是这边不太好理解
		//后置++是先放参与加运算再自身+1
	}

ok了思路就是这么多

AC code

// Problem: 
//     Good Subarrays
//   
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF1398C
// Memory Limit: 250 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<iostream>
#include<algorithm>
//#include<cstdio>
#include<map>
#define ll long long 
#define int long long
#define endl '\n'
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>(b);i--)
#define N 100010 //1e6+100 
 
using namespace std;
int a[N],n,t,sum[N];
//本题需要用long long为了图方便我就直接宏定义把int定义成long long了
string nums;
map<int,int>m;
void solve(){
	m.clear();
	int res=0;
	m[0]=1;//这句话一定要打!
	//这是为什么呢?因为如果当前前缀和(表示为1~i个数的和)等于这段区间长度i那么测试就是sum[i]-i=0那就不用去找别的数了肯定是好子数组
	//这里其实也是一个比较难理解的点
	//这样理解可能比较好动m[0]=1就表示m[sum[0]-0]=1也就是说有符合sum[0]-0==sum[i]-i这边(i仅表示第一次遇到,i=0的时候是他第0次遇到,所以当第一次遇到之前,他们已经相遇过一次,方法就按上面的方法继续处理下去)
	//这是个重难点,需要思考一下
	cin>>n>>nums;
	rep(i,1,n) {
		a[i]=nums[i-1]-'0';
		sum[i]=sum[i-1]+a[i];
		res+=m[sum[i]-i]++;
	}

    cout<<res<<endl;
}
signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>t;
	while(t--) solve();
	return 0; 
} 

有问题请评论或私信我,谢谢!

有共同学习需求的可以加入洛谷团队:https://www.luogu.com.cn/team/66731

标签:这边,Good,遇到,Subarrays,sum,个数,long,CF1398C,rep
From: https://www.cnblogs.com/Illuminated/p/18027972

相关文章

  • CF1295F - Good Contest
    题意:\(a_i\)​是在\([l_i​,r_i]\)上均匀随机分布的整数,求\(a_{1\dotsn}\)​单调不增的概率。对\(998244353\)取模。\(2\len\le50,0\lel_i\ler_i\le998244351\)。首先可以把概率转化为总方案数在除以\(\prodr_i-l_i+1\),考虑出朴素的dp,设\(f_{i,j}\)为$选......
  • C1. Good Subarrays (Easy Version)
    找子数组的个数双指针#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;constintN=2e5+10;inta[N];voidsolve(){ intn; cin>>n; for(inti=1;i<=n;i++)cin>>a[i]; intl=1,r=1; intans=0; while(l<=r){ if(l>n||r>......
  • D. Good Trip
    原题链接题解1.把分数中的除法用乘以逆元表示,在求模运算里的除法都可以用乘以逆元代替(如果除法的结果为整数),但是这里规定了可以用其表示,那就用其表示2.读题code#include<bits/stdc++.h>intmod=1e9+7;//确保mod是一个整数usingnamespacestd;//快速幂函数,计算base......
  • CF316G3 Good Substrings
    题意简述有一个字符串\(s\)和\(n\)条限制,每条限制给出字符串\(t_i\)和两个整数\(l_i,r_i\),要求一个字符串要满足在\(t_i\)中的出现次数要在\([l_i,r_i]\)之间。求\(s\)有多少本质不同的子串满足所有限制。\(|s|,\max|t|\le5\times10^4,n\le10\)分析“本质不同......
  • Educational Codeforces Round 145 (Rated for Div. 2)C. Sum on Subarrays(构造)
    很意思的一道构造题题意:给一个\(n、k\),让构造长度为n的数组满足,子数组为整数的个数为k个,负数的为\(k-(n+1)*n/2\),每个数的范围为\([-1000,1000]\)这种构造题可以考虑就是前一段可以一直用一样的、最小的。我们观察可以发现\(k+k-(n+1)*n/2=(n+1)*n/2\)也就是所有子数组......
  • [ABC327G] Many Good Tuple Problems 题解
    Description对于一对长度均为\(M\)且元素值在\(\left[1,N\right]\)之间的序列\((S,T)\),定义其为好的当且仅当:存在一个长度为\(N\)的\(01\)序列\(X\),使得其满足如下条件:对于任意\(i\in\left[1,M\right]\),有\(X_{S_i}\neqX_{T_i}\)。给定\(N,M\),求在......
  • Good Bye 2023
    A本质就是判断\(\prod_{i=1}^{n}b_i\)是否能整除\(2023\)。输出被移除的数,只要令\(k-1\)个为\(1\),剩下的一个随便算算即可。B非常难绷。首先将\(a\)和\(b\)都除以\(\operatorname{gcd}(a,b)\),并记录原来的\(\operatorname{gcd}(a,b)\)为\(t\)。如果\(a=1\),......
  • D. Good Trip
    D.GoodTripThereare$n$childreninaclass,$m$pairsamongthemarefriends.The$i$-thpairwhoarefriendshaveafriendshipvalueof$f_i$.Theteacherhastogofor$k$excursions,andforeachoftheexcursionsshechoosesapairofchildrenran......
  • 数学概率拆分——cf_921_D.Good Trip
    目录问题概述思路想法参考代码问题反思问题概述原题参考:D.GoodTrip大致意思就是一个老师带着n个孩子,其中有m对是朋友,每对朋友之间有一个友谊值,不是朋友的则是0,这个老师要出去玩k次,每次可以带上两个小朋友(为什么不能一起带,这是偏爱!!!),如果这两个小朋友是朋友关系的话,那么他们的......
  • CF921 D. Good Trip
    题面代码点击查看代码#include<bits/stdc++.h>usingnamespacestd;#defineIOSios::sync_with_stdio(0);cin.tie(0);cout.tie(0);#definerep(i,a,n)for(inti=a;i<=n;i++)#defineper(i,a,n)for(inti=n;i>=a;i--)#definefirstfi#defineseconfse#defi......