\(\sf E-Crypto\ Lights\)

题目

给定长度为 \(n\) 的初始均为 \(0\) 的序列,你有如下操作:

  1. 值为 \(0\) 的点之间等概率选择一个点变成 \(1\)
  2. 如果有两个值为 \(1\) 的点距离 \(<k\),结束操作。否则回到 1.

你需要求出最终序列 \(1\) 个数的期望。

解法

首先,“最终序列 \(1\) 个数的期望” 等价于 “结束时操作次数期望”。

这样不太好算,因为 “结束时” 和 “结束前” 两个状态不太一样。于是我们可以再进行一步转化:结束前操作次数期望 \(+1\)

钦定结束前操作次数为 \(i\),那么到达每个操作次数为 \(i\) 状态的概率是 \(\frac{1}{n\times (n-1)\times...\times (n-i+1)}\) 也即 \(\frac{(n-i)!}{n!}\)

那么如何计算合法的状态呢?考虑如果没有 \(k\) 的限制,合法种类数就是 \(\text{C}_{n}^i \times i!\)。有一个奇妙的发现,就是合法状态每两个 \(1\) 之间必定有至少 \(k-1\)\(0\)!那么类似小球入盒的解决方案,我们把每两个 \(1\) 之间一定有的 \(k-1\)\(0\) 先抛掉,那么就剩下 \(n-(k-1)(i-1)\) 个位置,我们在里面任选 \(i\) 个位置,再在每两个 \(1\) 之间插入 \(k-1\)\(0\)。容易发现这是等价于原问题的,因为一段 \(0\) 的相对位置对方案没有影响。

所以有:

\[\text{Ans}=1+\sum_{i=1}^n \text{C}_{n-(k-1)(i-1)}^i\times i!\times \frac{(n-i)!}{n!} \]


\(\sf G - Try\ Booking\)

解法

既然要求互不相交,你会发现长度 \(x\) 最多只能选 \(\frac{n}{x}\) 个区间。所以惊喜地发现总区间个数是 \(\sum_{x=1}^n \frac{n}{x}\approx n\ln n\)

对于每个 \(x\),如果我们找到编号最小的区间 \([l,r]\),那么接下来需要在 \([1,l-1]\cup [r+1,n]\) 中寻找编号最小的区间… 以此类推。

问题转化为在查询区间中找编号最小的区间。不过这不能用线段树维护,因为线段树可能会出现查询区间与小区间相交的情况。

我想用 \(\mathtt{cdq}\) 分治!但是注意到此题的询问区间是动态的,必须询问到上一个编号最小的区间才能确定下一个询问。

那就… 树套树!

代码

还是放一个吧…


\(\sf H - Hopping \ Around \ the \ Array\)

解法

首先发现设计关于 \(i\rightarrow j\) 的最小步数的状态是不现实的,它的范围高达 \(4e8\)。既然询问只问 \((l_i,r_i,k_i)\),为什么不试试类似分块的做法,一块块地拼凑出答案?

事实上,这个问题可以用倍增巧妙地解决。

\(dp_{k,i,j}\) 表示删除不超过 \(k\) 个点,从 \(i\) 开始走 \(2^j\) 步能到达的最远位置。

由于 \(k\) 比较小,我们可以枚举 \(k_1,k_2\) 来进行转移:

\[dp_{k_1+k_2,i,j}=\max_{p=i}^{dp_{k_1,i,j-1}}dp_{k_2,p,j-1} \]

具体可以用 \(\mathtt{st}\) 表来实现。

如何统计答案?想想我们是如何用倍增求解 \(\rm lca\) 的,这里也类似:从大到小枚举 \(2^j\) 步,用 \(\mathtt{st}\) 表维护对应步数 \(dp\) 值的区间 \(\max\)。对于每个询问,定义 \(f_k\) 为删除不超过 \(k\) 个点从 \(l_i\) 能走到的最远的小于 \(r_i\) 的位置,每枚举一个步数就用类似于上文的转移来转移 \(f\) 值,如果此时 \(f_{k_i}<r_i\) 就说明可以走这个步数,否则就将 \(f\) 回退到原来的状态。

最后将每个询问的步数 \(+1\) 就是答案。

整体时间复杂度约为 \(\mathcal O(900\times n\log n)\)

代码

下次高维 \(\mathtt{dp}\) 再不按循环顺序来我就是 \(\mathtt{sb}\)

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#include <cstdio>

#define rep(i,_l,_r) for(signed i=(_l),_end=(_r);i<=_end;++i)
#define fep(i,_l,_r) for(signed i=(_l),_end=(_r);i>=_end;--i)
#define print(x,y) write(x),putchar(y)

template <class T> inline T read(const T sample) {
    T x=0; int f=1; char s;
    while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
    while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
    return x*f;
}
template <class T> inline void write(const T x) {
    if(x<0) return (void) (putchar('-'),write(-x));
    if(x>9) write(x/10);
    putchar(x%10^48);
}
template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}

const int maxn=2e4+4;

int n,q,lg[maxn],a[maxn],st[32][18][maxn],dp[18][32][maxn],ans[maxn],f[maxn][32],tmp[32];
struct node {
	int l,r,k;
} s[maxn];

void init() {
	rep(i,2,n) lg[i]=lg[i>>1]+1;
}

int Query(int k,int l,int r) {
	int d=lg[r-l+1];
	return Max(st[k][d][l],st[k][d][r-(1<<d)+1]);
}

int main() {
	n=read(9),q=read(9); init();
	int lgn=lg[n]+1;
	rep(i,1,n) a[i]=read(9);
	rep(k,0,30) rep(i,1,n) dp[0][k][i]=Min(n,i+a[i]+k);
	rep(j,1,lgn) {
		rep(k,0,30) rep(i,1,n) st[k][0][i]=dp[j-1][k][i];
		rep(k,0,30) rep(i,1,lgn) rep(p,1,n)
			if(p+(1<<i)-1<=n)
				st[k][i][p]=Max(st[k][i-1][p],st[k][i-1][p+(1<<i-1)]);
			else break;
		rep(k1,0,30) rep(k2,0,30) {
			if(k1+k2>30) break;
			rep(i,1,n) dp[j][k1+k2][i]=Max(dp[j][k1+k2][i],Query(k1,i,dp[j-1][k2][i]));
		}
	}
	rep(i,1,q) {
		s[i].l=read(9),s[i].r=read(9),s[i].k=read(9);
		if(s[i].l==s[i].r) ans[i]=-1;
		else rep(j,0,s[i].k) f[i][j]=s[i].l;
	}
	fep(j,lgn,0) {
		rep(k,0,30) rep(i,1,n) st[k][0][i]=dp[j][k][i];
		rep(k,0,30) rep(i,1,lgn) rep(p,1,n)
			if(p+(1<<i)-1<=n)
				st[k][i][p]=Max(st[k][i-1][p],st[k][i-1][p+(1<<i-1)]);
			else break;
		rep(i,1,q) {
			if(ans[i]==-1) continue;
			rep(k,0,s[i].k) tmp[k]=0;
			rep(k1,0,s[i].k) rep(k2,0,s[i].k) {
				if(k1+k2>s[i].k) break;
				tmp[k1+k2]=Max(tmp[k1+k2],Query(k1,s[i].l,f[i][k2]));
			}
			if(tmp[s[i].k]<s[i].r) {
				ans[i]+=(1<<j);
				rep(k,0,s[i].k) f[i][k]=tmp[k];
			}
		}
	}
	rep(i,1,q) print(ans[i]+1,'\n');
	return 0;
}
posted on 2021-06-02 18:15  Oxide  阅读(55)  评论(0编辑  收藏  举报