Codeforces 314A. Sereja and Contest

本文详细解析了 Codeforces 第 314 场比赛中的 A 题,从朴素思路出发,逐步优化算法,最终通过分析得出更高效的解法。文章不仅提供了完整的代码实现,还深入探讨了题目的数学原理和优化技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Link: http://codeforces.com/problemset/problem/314/A

A. Sereja and Contest
time limit per test: 2 seconds
memory limit per test: 256 megabytes
input: standard input
output: standard output

During the last Sereja's Codesecrof round the server crashed many times, so the round was decided to be made unrated for some participants.

Let's assume that n people took part in the contest. Let's assume that the participant who got the first place has rating a1, the second place participant has rating a2, ..., the n-th place participant has rating an. Then changing the rating on the Codesecrof site is calculated by the formula .

After the round was over, the Codesecrof management published the participants' results table. They decided that if for a participant di < k, then the round can be considered unrated for him. But imagine the management's surprise when they found out that the participants' rating table is dynamic. In other words, when some participant is removed from the rating, he is removed from the results' table and the rating is recalculated according to the new table. And of course, all applications for exclusion from the rating are considered in view of the current table.

We know that among all the applications for exclusion from the rating the first application to consider is from the participant with the best rank (the rank with the minimum number), for who di < k. We also know that the applications for exclusion from rating were submitted by all participants.

Now Sereja wonders, what is the number of participants to be excluded from the contest rating, and the numbers of the participants in the original table in the order of their exclusion from the rating. Pay attention to the analysis of the first test case for a better understanding of the statement.

Input

The first line contains two integers n, k (1 ≤ n ≤ 2·105,  - 109 ≤ k ≤ 0). The second line contains n space-separated integers a1, a2, ..., an (1 ≤ ai ≤ 109) — ratings of the participants in the initial table.

Output

Print the numbers of participants in the order in which they were removed from the table. Print the initial numbers of the participants, that is, the numbers that the participants had in the initial table.

Sample test(s)
Input
5 0
5 3 4 1 2
Output
2
3
4
Input
10 -10
5 5 1 7 5 1 2 4 9 2
Output
2
4
5
7
8
9
Note

Consider the first test sample.

  • Initially the sequence of the contest participants' ratings equals [5, 3, 4, 1, 2]. You can use this sequence to calculate the sequence of rating changes: [0, -9, -13, 8, 14]. According to the problem statement, the application of the participant who won the second place will be considered first.
  • As soon as the second place winner is out from the ratings, the participants' rating sequence will equal [5, 4, 1, 2]. By this sequence you can count the new sequence of rating changes: [0, -8, 2, 6]. According to the problem statement, the application of the participant who won the second place will be considered. Initially this participant won third place.
  • The new rating sequence equals [5, 1, 2], the new sequence of rating changes equals [0, -1, 1]. The second place participant's application is taken into consideration, initially this participant won the fourth place.
  • The new rating sequence equals [5, 2], the new sequence of rating changes equals [0, 0]. No more applications will be considered.

Thus, you should print 2, 3, 4.

先贴一个没头脑的朴素思路的代码:

 1 #include <iostream>
 2 #include <vector>
 3 using namespace std;
 4 #include <stdio.h>
 5 struct player
 6 {
 7     int num;
 8     int rating;
 9 };
10 int which_to_remove(vector<player> rating,int k){
11     int len = rating.size();
12     int i;
13     vector<long long> rating_change(len, 0);
14     for (i = 1;i < len ; ++i)
15     {
16         for (int j = 1; j <= i-1; ++j)
17         {
18             rating_change[i] += rating[j].rating * (j-1) - (len-1-i) * rating[i].rating;
19         }
20     }
21     for (i = 1; i < len; ++i)
22     {
23 
24         if (rating_change[i]<k)
25         {
26             break;
27         }
28     }
29 
30     return i;
31 }
32 
33 
34 int main(int argc, char *argv[])
35 {
36     int n,k;
37     scanf("%d %d",&n,&k);
38     vector<player> rating(n+1);
39     for (int i = 1; i <= n; ++i)
40     {
41         rating[i].num = i;
42         scanf("%d",&rating[i].rating);
43     }
44     while(1){
45     int result = which_to_remove(rating,k);
46     if(result == rating.size())
47         break;
48     else
49         {
50         printf("%d\n",rating[result].num);
51         rating.erase(rating.begin()+result);
52         }
53     }
54     return 0;
55 }
View Code

没有任何思考写出的代码,基本就是把题目中叙述的过程写了下来:每轮计算一次rating change,计算完后再遍历找符合要求的剔除对象,没有符合要求的剔除对象时停止。

抛开效率不说,代码本身就又有错,从原题的叙述来看,rating change的值int型肯定会溢出的。我虽然用了long long型来储存结果,但在中间过程中实际已经溢出了,最后转成long long型毫无意义。正确的做法是把struct中的rating也改为long long类型。这个错误导致我一直在Test 4 WA。

改正之后果不其然的TLE了。这时我们分析一下题中的公式,可以发现这样一个结论:如果某一轮元素A及他之前的元素都未被剔除(即该轮的剔除发生在元素A之后),下一轮A及A之前的元素是不可能被剔除的。

根据上面的结论,其实只要遍历一次即可求出所有被剔除的元素。中间维护一下用于计算rating change的几个量即可。

AC代码:

#include <iostream>
#include <vector>
using namespace std;
#include <stdio.h>
int main (int argc, const char* argv[])
{

    int n, k, delete_count;
    long long rating, rating_change, common_factor;
    vector<int> trash;

    scanf ("%d%d", &n, &k);
    scanf ("%I64d", &rating);

    delete_count = 0;
    common_factor = 0;

    for (int i = 2; i <= n; i++)
    {
        scanf ("%I64d", &rating);
        rating_change = common_factor - (n - i) * rating * (i - delete_count - 1);

        if (rating_change < k)
        {
            trash.push_back (i);
            delete_count ++;
        }
        else
        {
            common_factor += (i - delete_count - 1) * rating;
        }
    }

    for (int i = 0; i < delete_count; i++)
    {
        printf ("%d\n", trash[i]);
    }

    return 0;

}
View Code

注意long long的输入输出一定要用%I64d,我之前用%d在本机正常(TDM-GCC),但是在CF那边用GNU C++结果就会错。

总结:

1. 好久不做题手真的生了不少。

2. Codeforces的题出的挺不错的。

转载于:https://www.cnblogs.com/jerry-wangbin/archive/2013/06/11/Codeforces_314A.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值