[补题记录]2019-2020 ICPC (NWERC 2019) -A - Average Rank

A - Average Rank Gym - 102500A

题意

有一些队,每周都有一些队过题,每过一题分数+1,问这些周之后每队的平均rank

题解

首先观察题目可以发现,规律就是当这个人分数增加时,所有和他分数相同的人rank+1,同时他的rank-(他当前分数+1的这个分数有多少人)
那么我们直接模拟??会T掉

对于每个人,只有在他的分数变化时再去更新 虽然优化了,但也会T掉

所以就有了一种特别妙的做法,因为每次要更新的人的分数是一样的,那我们不去记录每次跟他同样分数的rank变化,可以记下来当前point的贡献,记下来上次更新时的已经加完的贡献,在下次更新时,只去加贡献的差值

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lowbit(a) ((a) & -(a))
#define clean(a, b) memset(a, b, sizeof(a))
const int mod = 998244353;
const int inf = 0x3f3f3f3f;
const int maxn = 3e5 + 9;
typedef pair<int,int>P;

int _;

//========================================================================
ll po[maxn],rk[maxn],last[maxn],sum[maxn],num[maxn],pre[maxn];
//========================================================================
int main()
{
    int n,m,x,k;
    scanf("%d%d",&n,&m);
    // for(int i=1;i<=n;i++) rk[i]=1;
    for(int i=1;i<=m;i++)  
    {
        scanf("%d",&k);
        for(int j=1;j<=k;j++)
        {
            scanf("%d",&x);

            //当前分被更新
            num[po[x]]+=rk[po[x]]*(i-1-last[po[x]]);   // 这个分数当前贡献 += 这个分数保持了多少轮 * 这个分数当前名次 
            last[po[x]]=i-1;  //记录上次更新的位置
            rk[po[x]]++;  //这个分的排名下降了 跟他名次相同的人的名次下降了
            sum[x]+=num[po[x]]-pre[x];  // 这个人添加的贡献为 当前分的总贡献-上次分的贡献

            //+1的分数也被更新
            po[x]++;  // 这个人分数+1
            num[po[x]]+=rk[po[x]]*(i-1-last[po[x]]);  //这个分当前贡献  += 这个分数保持了多少轮 * 这个分数当前名次 
            last[po[x]]=i-1;  //记录上次更新的位置
            pre[x]=num[po[x]];  //记录下这个人当前的贡献变为涨完分之后的贡献

        }
    }
    for(int i=1;i<=n;i++)  //把还没更新人的贡献加上
    {
        num[po[i]]+=rk[po[i]]*(m-last[po[i]]);
        last[po[i]]=m;
        sum[i]+=num[po[i]]-pre[i];
    }
    for(int i=1;i<=n;i++) printf("%.9f\n",1.0+1.0*sum[i]/m);  //计算的是贡献的增量 ,没有算初始增量所以要加上
    return 0;
}
posted @ 2020-08-16 19:55  L·S·D  阅读(573)  评论(0编辑  收藏  举报