Atcoder Grand Contest 023

023D Go Home

题目描述

点此看题

解法

直接判断当前状态的决策是困难的,我们不妨逆推整个过程。考虑最后电车一定是再 \(1/n\) 停止的,那么我们大胆猜测,如果 \(p_1\geq p_n\),那么电车会先到 \(1\) 处,如果 \(p_1<p_n\),那么电车会先到 \(n\) 处。下面给出 \(p_1\geq p_n\) 会先到 \(1\) 处的证明(另一部分可以类似地证明):

  • \(n=2\),显然成立。
  • \(n>2\) 并且 \(s>x_{n-1}\),则除了 \(n\) 都会投票往左走,结论成立。
  • \(n>2\) 并且 \(s\leq x_{n-1}\),则如果列车到达 \(1\) 之前没有到达过 \(n-1\),则结论成立;否则可以化归到第二种情况。

那么考虑 \(n\) 处到达的时间一定是 \(1\) 处到达的时间加上 \(x[n]-x[1]\),并且 \(n\) 就是最后到达的节点。那么等效子问题就特别明显了,我们让 \(p_1\leftarrow p_1+p_n\),然后把 \(n\) 删去,递归下去即可。递归的边界是不满足 \(x[l]<s<x[r]\),时间复杂度 \(O(n)\)

#include <cstdio>
#define int long long
const int M = 100005;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,s,x[M],p[M];
int calc(int l,int r,int f)
{
	if(s<=x[l]) return x[r]-s;
	if(s>=x[r]) return s-x[l];
	if(p[l]>=p[r])
	{
		p[l]+=p[r];
		return (f==r)*(x[r]-x[l])+calc(l,r-1,l);
	}
	p[r]+=p[l];
	return (f==l)*(x[r]-x[l])+calc(l+1,r,r);
}
signed main()
{
	n=read();s=read();
	for(int i=1;i<=n;i++)
		x[i]=read(),p[i]=read();
	printf("%lld\n",calc(1,n,p[1]<p[n]?1:n));
}

023E Inversions

题目描述

点此看题

解法

一看就只能算贡献,我们先考虑如何计算合法的排列数,首先把 \(a_i\) 排好序,设 \(p_i\) 表示排序后第 \(i\) 个元素在原序列上的位置,我们按照 \(a_i\) 的顺序填数,那么可供选择的方案是 \(a_i-i+1\)

\[t=\prod_{i=1}^{n}(a_i-i+1) \]

开始算贡献吧,考虑排序后序列上的两个位置 \(i<j\),我们对 \(p_i,p_j\) 的关系进行讨论。首先考虑 \(p_i<p_j\) 的情况,那么有贡献就需要 \(i\) 位置上填的数更大,考虑在总方案上略微修改,首先 \(i\) 的方案是 \(a_i-i+1\),根据等差数列选择 \(i,j\) 的方案是 \(\frac{(a_i-i+1)(a_i-i)}{2}\),注意 \(k\in(i,j)\) 的选择变少了 \(1\),综合考虑之后可以写出式子:

\[\frac{t(a_i-i)}{2(a_j-j+1)}\prod_{k\in(i,j)} \frac{a_i-i}{a_i-i+1} \]

对于 \(p_i>p_j\) 的情况,用总情况数去减就行了。

现在很容易 \(O(n^2)\) 计算,优化考虑把连乘拆分成前缀积和前缀积逆元,我们枚举扫描 \(j\),用树状数组就可以轻易维护 \(p_i\)\(p_j\) 的关系。注意可能遇到没有逆元的情况,这时候前缀 \([1,i]\) 是没有 \(p_i<p_j\) 的方案的,可以直接清空树状数组,时间复杂度 \(O(n\log n)\)

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int M = 200005;
const int MOD = 1e9+7;
#define int long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,t,ans,a[M],p[M],s[M],is[M],inv[M];
pair<int,int> d[M];
struct fenwick
{
	int tp,b[M],s[M];
	void add(int x,int y)
	{
		s[++tp]=x;
		for(int i=x;i<=n;i+=i&(-i))
			b[i]=(b[i]+y)%MOD;
	}
	int ask(int x)
	{
		int r=0;
		for(int i=x;i>=1;i-=i&(-i))
			r=(r+b[i])%MOD;
		return r;
	}
	void clear()
	{
		for(int o=1;o<=tp;o++)
			for(int i=s[o];i<=n;i+=i&(-i))
				b[i]=0;
		tp=0;
	}
}f,g;
signed main()
{
	n=read();inv[0]=inv[1]=1;
	for(int i=2;i<=n;i++)
		inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
	for(int i=1;i<=n;i++)
		a[i]=read(),d[i]={a[i],i};
	sort(d+1,d+1+n);t=1;
	for(int i=1;i<=n;i++)
	{
		int w=lower_bound(d+1,d+1+n,
			make_pair(a[i],i))-d;
		p[w]=i;t=t*max(0ll,a[i]-w+1)%MOD;
	}
	if(!t) {puts("0");return 0;}
	for(int i=1;i<=n;i++)
	{
		if(!s[i-1])
		{
			s[i-1]=is[i-1]=1;
			g.clear();
		}
		int x=a[p[i]];
		s[i]=s[i-1]*(x-i)%MOD*inv[x-i+1]%MOD;
		is[i]=is[i-1]*inv[x-i]%MOD*(x-i+1)%MOD;
		int d=s[i-1]*inv[x-i+1]%MOD;
		ans=(ans+i-1-f.ask(p[i]))%MOD;
		ans=(ans-(g.ask(n)-2*g.ask(p[i]))*d)%MOD;
		ans=(ans+MOD)%MOD;
		g.add(p[i],(x-i)*inv[2]%MOD*is[i]%MOD);
		f.add(p[i],1);
	}
	ans=ans*t%MOD;
	printf("%lld\n",ans);
}
posted @ 2022-03-16 22:59  C202044zxy  阅读(78)  评论(2编辑  收藏  举报