一些做题得到的东西

1.非递归的归并排序
我们可以用于思考一些题,
如果它可以等于左边部分加上右边部分加上跨左右的部分
如果可以优化成归并排序的方法,你可以尝试使用这个方法

#include <bits/stdc++.h>
using namespace std;
#define int long long

int n;

int help[1008611];
int arr[1008611];


void merge(int l,int m,int r){
    int i=l;
    int a=l;
    int b=m+1;
    while(a<=m&&b<=r){
        help[i++]=arr[a]<=arr[b]?arr[a++]:arr[b++];
    }

    while(a<=m){
        help[i++]=arr[a++];
    }
    while(b<=r){
        help[i++]=arr[b++];
    }
    for (int j = l; j <=r ; ++j) {
        arr[j]=help[j];
    }
}

void solve(){

    for(int l,m,r,step=1;step<n;step<<=1){

        l=0;
        while(l<n){
            m=l+step-1;
            if(m+1>=n){
                break;
            }
            r=min(l+(step<<1)-1,n-1);
            merge(l,m,r);
            l= r+1;
        }
    }
}



int32_t main() {
    cin>>n;
    for (int i = 0; i <n ; ++i) {
        cin>>arr[i];
    }
    solve();

    for (int i = 0; i < n; ++i) {
        cout<<arr[i];
    }
    return 0;
}

2.同余定理
题目K倍区间
如果两个前缀和除以k得到相同的余数,那么这两个前缀和之差一定是k的倍数
数学表达: 如果 sum[i] % k = sum[j] % k,那么 (sum[i] - sum[j]) % k = 0
举例
假设有序列 [3, 1, 4, 2],k = 3
前缀和序列为: [0, 3, 4, 8, 10]
各个前缀和对3取余: [0, 0, 1, 2, 1]
余数为0的位置: 0, 1
余数为1的位置: 2, 4
余数为2的位置: 3
因此可以构成的k倍区间数量 = C(2,2) + C(2,2) + C(1,2) = 1 + 1 + 0 = 2
详细解释一下这个组合计算过程:

当我们找到前缀和对k取余后相同的位置时,这些位置两两之间的区间和都是k的倍数。我们用组合数来计算这些位置能形成多少个区间。

在这个例子中:

code
序列: [3, 1, 4, 2]
前缀和: [0, 3, 4, 8, 10]
余数: [0, 0, 1, 2, 1]

余数为0的位置有两个:位置0和位置1

C(2,2) 表示从这2个位置中选择2个位置的组合数
C(2,2) = 1,即可以形成1个区间:(0,1)
余数为1的位置有两个:位置2和位置4

C(2,2) = 1,即可以形成1个区间:(2,4)
余数为2的位置只有一个:位置3

C(1,2) = 0,因为只有一个位置,无法形成区间

总的区间数 = 1 + 1 + 0 = 2

#include<iostream>
#include<string.h>
using namespace std;
int sett[100002];
long gcc[100002];
int main()
{
    int n,k;
    cin>>n>>k;
    long count=0;
    long sum=0;
    memset(gcc,0,sizeof(gcc));
    for(int i=0;i<n;i++)
    {
        cin>>sett[i];
        sum+=sett[i];//记录前缀和
        gcc[ sum%k ]++;//余数相同的区间
    }
    //余数相同的区间相减可以构成一个k倍区间
    count = gcc[0];
    for(int i=0;i<k;i++)
    {
        count+=gcc[i]*(gcc[i]-1)/2;
    }    
    cout<<count<<endl;
    return 0;
}
posted @ 2024-11-05 21:40  冬天的睡袋  阅读(0)  评论(0编辑  收藏  举报