1230. K倍区间(超级详细,小白入!!!)

1230. K倍区间(超级详细,小白入!!!)_第1张图片

输入样例:

5 2
1
2
3
4
5

输出样例:

6

这个题看到区间两个字,两眼一瞪可能就和前缀和差分有关

做题思路:

通过记录每个[1,r]区间值的和,看它前面是否出现过一个[1,l](l<=r),使得[l,r]区间的值能除尽k

 有同学就好奇,这个双重循环,搞两个指针l,r,直接卡区间不就完了,为啥要左端点都从1开始,因为数据范围不允许O(N^2)的时间复杂度

如下面我的第一次错误代码

#include
using namespace std;
const int N=100010;
int n,k,cnt;
long long a[N],f[N];

int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        f[i]=f[i-1]+a[i];
    }
    for(int i=0;i

思路和逻辑没问题,就是太暴力了,导致时间复杂度太高,TLE超时了!/(ㄒoㄒ)/~~

下面是我看一个大佬的,他将两重循环,直接缩减到一层 

 画个简图也就是这个意思 

1230. K倍区间(超级详细,小白入!!!)_第2张图片

#include
using namespace std;
const int N=100010;
int n,k;
int a[N],f[N],ans[N];//这里面存的是取余后的结果所有定义为int就行
long long cnt;

int main()
{
    cin>>n>>k;
    
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        f[i]=(f[i-1]+a[i])%k;
        //其实相当于求除每个左端点为第一个元素的前缀和除k的余数
        //然后如果前面存在余数相同的,说明咱们这个区间减去前面的区间结果为0,说明组合成的新区间可以除尽k
        //则可以使用排列组合进行两两配对,也就是前面有几个余数相同的,则就可以生成几个k倍区间
        cnt+=ans[f[i]];
        ans[f[i]]++;
    }
    cout<

太强了!膜拜大佬/(ㄒoㄒ)/~~

你可能感兴趣的:(暑假基础集训营,算法)