首页 > 其他 > 详细

zzuli-1758学渣的逆袭(离散化,二分,折半枚举)

时间:2015-11-24 12:53:46      阅读:345      评论:0      收藏:0      [点我收藏+]

http://acm.zzuli.edu.cn/problem.php?id=1785

思路:从每个数列中都取一个数字,然后求有多少种方案组成给你的那个数。

总共就4个数列,那么折半枚举(就是分两组枚举(复杂度为p1*p2+p3*p4))。暴力枚举的话是p1*p2*p3*p4;

然后所要求的数K,枚举第一组中所有的数d,然后K-p,在第二组中找k-p,找到了ans++;

第二组中的数范围是2*1e8,所以不能开数组记录那个数的次数,可以用map映射,但我写了后随然过了但用了2500Ms.

更高效率的 我用的是离散化,加二分找点,第二组数据中最多就300000个数,所以离散化一下就可以了,然后查询找点用二分。

复杂度为(p1*p2+p3*p4+log[p3*p4]);

 1 #include<stdio.h>
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<stdlib.h>
 5 #include<string.h>
 6 #include<map>
 7 int er(int n,int m,int k);
 8 void ju();
 9 int a[5][505];
10 int b[300000];
11 int c[300000];
12 int d[300000];
13 int h[300000];
14 int aa[5];
15 int z,q,ff;
16 using namespace std;
17 map<int ,int >my;
18 int main(void)
19 {
20     int n,i,j,k,p,x1,x2,x3,x4;
21     while(scanf("%d %d %d %d",&aa[0],&aa[1],&aa[2],&aa[3])!=EOF)
22     {
23         for(i=0; i<4; i++)
24             for(j=0; j<aa[i]; j++)
25                 scanf("%d",&a[i][j]);
26         ju();
27         scanf("%d",&n);
28         int t;
29         while(n--)
30         {
31             scanf("%d",&t);
32             int coutt=0;
33             for(i=0; i<z; i++)
34             {
35                 int yy=t-b[i];
36                 coutt+=er(0,q,yy);
37 
38             }
39             printf("%d\n",coutt);
40         }
41     }
42     return 0;
43 }
44 void ju()
45 {
46     int i,j,k,p;
47     z=0;
48     q=0;
49     for(i=0; i<aa[0]; i++)//折半枚举第一组
50     {
51         for(j=0; j<aa[1]; j++)
52         {
53             b[z++]=a[0][i]+a[1][j];
54         }
55     }
56     for(i=0; i<aa[2]; i++)//折半枚举第二组
57     {
58         for(j=0; j<aa[3]; j++)
59         {
60             c[q++]=a[2][i]+a[3][j];
61         }
62     }
63     sort(c,c+q);//离散化
64     memset(d,0,sizeof(d));
65     d[0]=1;
66     ff=0;
67     h[0]=0;
68     for(i=1; i<q; i++)
69     {
70         if(c[i]!=c[i-1])//去重
71         {
72             ff++;
73         }
74         d[ff]++;//离散化时将原来的点转为对应的点并记录出现个数
75         h[i]=ff;
76     }
77 
78 }
79 int er(int n,int m,int k)//二分找点
80 {
81     int i=(n+m)/2;
82     if(n>m)
83     {
84         return 0;
85     }
86     if(c[i]==k)
87     {
88         return d[h[i]];
89     }
90     else if(c[i]>k)
91     {
92         return er(n,i-1,k);
93     }
94     else return er(i+1,m,k);
95 }

 

zzuli-1758学渣的逆袭(离散化,二分,折半枚举)

原文:http://www.cnblogs.com/zzuli2sjy/p/4991094.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!