zoukankan      html  css  js  c++  java
  • Zigzags CodeForces

    给出一组数:

    寻找四元组的个数 

    (i,j,k,l)其中a[i]=a[k],并且a[j]=a[l]

    刚看到这个题的时候想到了记录每个数的个数,然后求前缀和以及后缀和。先枚举i和k,当a[i]和a[k]相等时,在枚举i和k之间的数,然后在将前缀和与后缀和相乘,但是这样复杂度是o(n^3),显然过不了。看了大佬的blog,发现有个更好的思路,我们现在枚举了i和k对吧,i-----k,而题目的要求是k---i---k---i,那就直接在i左边找个K并且在k后边找个i然后将他们出现的次数相乘就完了呗!

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=3e3+7;
    long long  preious_sum[N][N];//表示sum[i][j]表示前i个数,j出现的次数
    long long later_sum[N][N];
    int arr[N];
    int main(){
        int t;
        cin>>t;
        while(t--){
            int n;
            cin>>n;
            for(int i=1;i<=n;i++) {
                cin>>arr[i]; 
                preious_sum[i][arr[i]]++;
                later_sum[i][arr[i]]++; 
            }
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++){
                    preious_sum[i][j]+=preious_sum[i-1][j];
                } 
            }
            for(int i=n;i>=1;i--){
                for(int j=1;j<=n;j++){
                    later_sum[i][j]+=later_sum[i+1][j];
                } 
            }
            long long  ans=0;
            for(int i=1;i<=n;i++){
                for(int j=i+1;j<n;j++){
                    ans+=preious_sum[i-1][arr[j]]*later_sum[j+1][arr[i]];
                }
            }
            cout<<ans<<endl;
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++)
                    later_sum[i][j]=preious_sum[i][j]=0;
            }
        }
    
    
        return 0;
    }

     另外一种写法。

    code:

    #include <stdio.h>
    #define maxn 3010
    #define LL long long
    int a[maxn],cnt[maxn];
    int main(){
        int t,n,i,j,sum;
        LL ans;
        scanf("%d",&t);
        while(t--){
            scanf("%d",&n);
            for(i=1;i<=n;i++)scanf("%d",&a[i]);
            for(i=1;i<=n;i++)cnt[i]=0;
            ans=0;
        //i1---j2
        //当前循环枚举的是i1和j2,cnt[]记录的是a[i1]出现的次数.
        //j1---i1---j2---i2
        //当枚举到i1=i,j2=j时,sum记录的是从i到j各个数出现的和,而cnt[k]就是在i1之前元素k出现的次数。sum累加就相当于寻找a[j1]=a[j2]的过程
        //当a[i]==a[j]的时候,说明i2找到了,i2=j,然后就可以更新答案了,更新完之后,j继续往后,因为后边可能还会有和a[i]相等的元素,找到再累加。
            for(i=1;i<=n;i++){
                sum=0; 
                for(j=i+1;j<=n;j++){
                    if(a[i]==a[j])ans+=sum;
                    sum+=cnt[a[j]];
                }
                cnt[a[i]]++;//第i个数出现的次数
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    【第40套模拟题】【noip2011_mayan】解题报告【map】【数论】【dfs】
    【模拟题(63550802...)】解题报告【贪心】【拓扑排序】【找规律】【树相关】
    【模拟题(电子科大MaxKU)】解题报告【树形问题】【矩阵乘法】【快速幂】【数论】
    IMemoryBufferReference and IMemoryBufferByteAccess
    SoftwareBitmap and BitmapEncoder in Windows.Graphics.Imaging Namespace
    Windows UPnP APIs
    编译Android技术总结
    Windows函数转发器
    Two Ways in Delphi to Get IP Address on Android
    Delphi Call getifaddrs and freeifaddrs on Android
  • 原文地址:https://www.cnblogs.com/Accepting/p/13599121.html
Copyright © 2011-2022 走看看