• UVa-1152 4 Values Whose Sum Is 0


    一道学校里div2 的训练题

    题目大意是给出n(<=4000)行四列的数字(<=2^28),我们需要从每列中选取一个数字使得四个数字之和恰好为0,问有多少种选取方案。

    所有组合是4000的4次方直接爆掉了,但是可以二分。(O(N)=N^2logN)

    左边2列(4000*4000种)中各取一个数字求和,右边同理,排序后一个从小到大,另一个从大到小找。开始错的地方是没有考虑类似 "1 1 1 1"与 "-1 -1 -1 " 这种应该加 3*4 而不是++,于是就用了结构体数组将相同的和存在一起并计数。

     1 #include<bits/stdc++.h>
     2 #define EPS 1e-9
     3 using namespace std;
     4 
     5 typedef long long ll;
     6 const int INF=0x3f3f3f3f;
     7 const int MAXN=16000000+6;
     8 
     9 long ans;
    10 long Bin[2][MAXN];
    11 int cnt[2];
    12 int tot[2];
    13 int raw[4][4003];
    14 int N;
    15 
    16 struct Node{
    17     int dat,num;
    18 }BN[2][MAXN];
    19 
    20 void getBin(int t){
    21     for(int i=0;i<N;++i){
    22         for(int j=0;j<N;++j){
    23             Bin[t][cnt[t]++]=raw[2*t][i]+raw[2*t+1][j];
    24         }
    25     }
    26 }
    27 
    28 int main(){
    29     //freopen("data.out","w",stdout);
    30     int Test;
    31     scanf("%d",&Test);
    32     for(int cntT=1;cntT<=Test;++cntT){
    33         ans=0;cnt[0]=cnt[1]=0;
    34         tot[0]=tot[1]=0;
    35         scanf("%d",&N);
    36         for(int i=0;i<N;++i){
    37             for(int j=0;j<4;++j){
    38                 scanf("%d",&raw[j][i]);
    39             }
    40         }
    41         getBin(0);
    42         getBin(1);
    43         sort(Bin[0],Bin[0]+cnt[0]);
    44         sort(Bin[1],Bin[1]+cnt[1]);
    45 
    46         for(int i=0;i<2;++i){
    47             BN[i][tot[i]].dat=Bin[i][0];
    48             BN[i][tot[i]++].num=1;
    49             for(int j=1;j<cnt[i];++j) {
    50                 if(Bin[i][j]==BN[i][tot[i]-1].dat)
    51                     BN[i][tot[i]-1].num+=1;
    52                 else{
    53                     BN[i][tot[i]].dat=Bin[i][j];
    54                     BN[i][tot[i]++].num=1;
    55                 }
    56             }
    57         }
    58 
    59         for(int i=0,j=tot[1]-1;i<tot[0];++i){
    60             while(BN[0][i].dat+BN[1][j].dat>0&&j>=1) j--;
    61             if(BN[0][i].dat+BN[1][j].dat>0) break;
    62 
    63             if(BN[0][i].dat+BN[1][j].dat==0) ans+=BN[0][i].num*BN[1][j].num;
    64             else if(BN[0][i].dat+BN[1][j].dat<0) continue;
    65         }
    66         printf("%ld
    ",ans);
    67         if(cntT!=Test) puts("");
    68     }
    69     return 0;
    70 }
    View Code

    数据会爆而且又是求和的性质啥的就应该往二分想。

  • 相关阅读:
    准备工作
    小黄衫感言
    2021软件工程总结
    4 20210412-1 原型设计作业
    2021软工-软件案例分析
    202103226-1 编程作业
    《构建之法》——读后感
    2021软件工程-第一周作业01准备工作
    Arthas笔记
    自定义 Web 容器
  • 原文地址:https://www.cnblogs.com/Kiritsugu/p/9325766.html
Copyright © 2020-2023  润新知