2018牛客多校第5场 take

感觉我和队友都是轮流考场上写出来然后对拍拍不出错然后过不了题。。。我队都喜欢在代码下毒。。。而且牛客的评判很畸形,第1个点错就不判了,告诉你通过0%的case,然而我们实在是没想到会错在什么地方。

我们考虑每一个点的贡献,那么就是他之前所有比他大的或者等于他的都不出现且比他小的要出现的概率乘以他出现的概率,概率再乘以交换的次数贡献也就是1.然后当前点被计算了以后,如果后面还要计算,计算比当前点小的点的概率时还要算上当前点不出现的概率,于是就需要把比当前点小的全部乘以这个点不出现的概率,今天学习了一波树状数组倒过来,然后做乘法,就可以直接变成单点乘就是区间乘,神神奇奇

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxl 100010
#define mod 998244353

using namespace std;

int n,cnt,tot,ans;
int inv100,d[maxl],b[maxl],p[maxl];
struct node
{
	int num,ind;
}a[maxl];

inline int qp(int a,int b)
{
	int ans=1,cnt=a;
	while(b)
	{
		if(b&1)
			ans=(1ll*ans*cnt)%mod;
		cnt=(1ll*cnt*cnt)%mod;
		b>>=1;
	}
	return ans;
}

inline bool cmp(const node &x,const node &y)
{
	return x.num<y.num;
}

inline void prework()
{
	inv100=qp(100,mod-2);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&p[i],&a[i].num);
		a[i].ind=i;p[i]=(1ll*p[i]*inv100)%mod;
	}
	sort(a+1,a+1+n,cmp);
	cnt=1;d[a[1].ind]=cnt;
	for(int i=2;i<=n;i++)
	if(a[i].num==a[i-1].num)
		d[a[i].ind]=cnt;
	else
		++cnt,d[a[i].ind]=cnt;
}

inline int ask(int i)
{
	int s=1;
	while(i)
	{
		s=1ll*s*b[i]%mod;
		i-=i&-i;
	}
	return s;
}

inline void add(int i,int x)
{
	while(i<=cnt)
	{
		b[i]=1ll*b[i]*x%mod;
		i+=i&-i;
	}
}

inline void mainwork()
{
	for(int i=0;i<=cnt;i++)
		b[i]=1;
	ans=0;
	for(int i=1;i<=n;i++)
	{
		ans=(ans+1ll*ask(cnt-d[i]+1)*p[i]%mod)%mod;
		add(cnt-d[i]+1,(1-p[i]+mod)%mod);
	}
}

inline void print()
{
	printf("%d\n",ans);
}


int main()
{
	while(~scanf("%d",&n))
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}




 

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/81383884