2016 ACM-ICPC 青岛站网络赛G题 题解

【参考博客】【https://blog.csdn.net/Tawn0000/article/details/82255682】

 题意:

将n个数按照每k个一组来合并,合并需要花费的cost是两个数的长度和,问:在T的消费内将所有的数合并所需的最小的k。

分析:

合并之前要处理一下零头,因为每次取k个一直到最后一步剩下的数的个数可能会少于k个,这样的结果就是合并的cost更大了,举个例子:1 2 3 4 5 6,k=4时,先选1 2 3 4然后再5 6 10 是31,但是因为零头有3,先处理3个零头,即:先取1 2 3然后是4 5 6 6 ,是27。显然27<31。

和被参考的那边博主一样,我也是一开始按照二分+优先队列的思路来进行考虑的,最后在O(n logn logn)的复杂度下TLE了。

如果采用双队列(一个队列存原来的数(从小到大排序后再入队),记为队列p1,另一个队列存合并后的数,记为队列p2),时间复杂度是O(n logn)。

双队列具体操作是取p1中k个原来的数相加,加完之后的值和p2队列取出的值数比较,取小的数加入p2(记得pop掉被取队列中的数),因为原队列的数按照从小到大的顺序排列的,所以一定会满足先入队的数比后入队的数小!。这样一来就会使得参与合并的数总是从小的开始。

AC code:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 queue<int> q1,q2;
 5 int a[100010];
 6 int n,T;
 7 bool P(int mid)
 8 {
 9     while(q1.size())    q1.pop();
10     while(q2.size())    q2.pop();
11     for(int i=0;i<n;i++)    q1.push(a[i]);
12     ll res=0;
13     int t=(n-1)%(mid-1);
14     if(t)
15     {
16         int p=0;
17         for(int i=0;i<t+1&&!q1.empty();i++)
18         {
19             p+=q1.front();
20             q1.pop();
21         }
22         res+=p;
23         q2.push(p);
24     }
25     while(1)
26     {
27         int p=0;
28         for(int i=0;i<mid;i++)
29         {
30             int x=99999999,y=99999999;
31             if(q1.empty()&&q2.empty())    break;
32             if(!q1.empty())    x=q1.front();
33             if(!q2.empty())    y=q2.front();
34             if(x<y)
35             {
36                 p+=x;
37                 q1.pop();
38             }
39             else
40             {
41                 p+=y;
42                 q2.pop();
43             }
44         }
45         res+=p;
46         if(res>T)    return true;
47         if(q1.empty()&&q2.empty())    break;
48         q2.push(p);
49     }
50     if(res>T)    return true;
51     else return false;
52 }
53 int main()
54 {
55     //freopen("input.txt","r",stdin);
56     int t;
57     scanf("%d",&t);
58     while(t--)
59     {
60         scanf("%d%d",&n,&T);
61         for(int i=0;i<n;i++)
62         {
63             scanf("%d",&a[i]);
64         }
65         sort(a,a+n);
66         int sd=1,ed=n;
67         while(ed - sd > 1)
68         {
69             int mid=sd+(ed-sd)/2;
70             if(P(mid))    sd=mid;
71             else ed=mid;
72         }
73         printf("%d\n",ed);
74     }
75 }
View Code

猜你喜欢

转载自www.cnblogs.com/cautx/p/11443959.html