训练赛9.7

source:

2019-2020 ICPC Northwestern European Regional Programming Contest (NWERC 2019)

Solved A B C D E F G H I J K
7 / 11 Ø - O - O O O Ø O - -

C贪心,E 签到,但注意边界判断条件和浮点数精度误差 F并查集 I签到。
G题翻译出锅,题目中的输入的概率只可作为权值,各元素随机选取,注意判断特殊情况k==1

A

一眼为\(O(nw)\)模拟。发现总修改小于1e6,需要从此入手解题。
每次+1时,改变的排名只有输入值x和原来与x同分的人。
可以用lazy标记记录修改,用类似线段树的方式均摊复杂度。

下面结合代码变量名再理一次思路

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read(){
	int x=0,f=1;char c=getchar();
	for(;!isdigit(c);c=getchar())c=='-'?f=-1:1;
	for(;isdigit(c);c=getchar()) x=x*10+c-'0';
	return x*f;
}
const int maxn=1e6+1000;
int n,w;
ll lazy[maxn],num[maxn],rk[maxn],pre[maxn];
//lazy[p[i]]值为p[i]的点上次被修改的时间
//num[p[i]]值为p[i]的点,排名的累计量
//rk[p[i]]值为p[i]的点,当前排名
//pre[i]为i点上次修改后排名的累计量
ll p[maxn];//i号元素分数
ll ans[maxn];//排名总和,第i名作为第i-1名记录
signed main(){
	cin>>n>>w;
	for(int i=0;i<w;i++){
		int k=read();
		for(int j=1;j<=k;j++){
			ll x=read();
			num[p[x]]+=rk[p[x]]*(i-lazy[p[x]]);//1 集中处理两次修改之间的排名累计量
			lazy[p[x]]=i;
			rk[p[x]]++;
			ans[x]+=num[p[x]]-pre[x];//2 这段时间排名的增量
			
			p[x]++;
			num[p[x]]+=rk[p[x]]*(i-lazy[p[x]]);
			lazy[p[x]]=i;
			pre[x]=num[p[x]];//3 
                        //1,2,3步是精髓
		}
	}
	for(int i=1;i<=n;i++){
		num[p[i]]+=rk[p[i]]*(w-lazy[p[i]]);
		lazy[p[i]]=w;
		ans[i]+=num[p[i]]-pre[i];
		printf("%.8lf\n",(1.0+1.0*ans[i]/w));
	}
	return 0;
}
posted @ 2022-09-18 22:41  xyc1719  阅读(29)  评论(0)    收藏  举报