20201023 day43 模拟(十六)

1 The magic of WHH

problem

长为\(n\)的序列,每次可以将相同数字之间的其他数字变成这个数字,可以得到多少种不同的序列?可以不操作。

solution

\([i,j]\)之间的颜色相同,则\([i,j]\)之间的操作是没有必要进行的。即每个位置只能与两侧最近的同色位置操作。
\(f(i)\)表示只考虑前\(i\)个位置的方案数,考虑加入位置\(i\)而上一个与\(i\)相同的位置是\(j\)

  1. 若这样的\(j\)不存在,则加入的位置没有贡献,\(f(i)=f(i-1)\)
  2. 如果存在,就要加上把\([j,i]\)染上颜色的贡献,此时注意\(j=i-1\)时染色是无效的,不会产生新的方案。

于是有\(f(i)=f(i-1)+[i-j>1]f(j)\),加上\(f(j)\)是因为将\([j,i]\)染色后,不影响\(j\)向前染色。

thoughts

0pts:统计数字出现的个数,用组合数的知识。(一个随随便便想想都知道极其错误的方法)
0pts:用队列维护区间长度。(其实这种模拟起来很复杂的题应该果断放弃模拟?)

code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
int read()
{
	int a = 0,x = 1;char ch = getchar();
	while(ch > '9' || ch < '0') {if(ch == '-') x = -1;ch = getchar();}
	while(ch >= '0' && ch <= '9') {a = a*10 + ch-'0';ch = getchar();}
	return a*x;
}
const int N=1e6+7;
const ll P=1e9+7;
int t[N],arr[N];
ll f[N];
int main()
{
	int n = read();f[0] = 1;
	for(int i = 1;i <= n;i ++) {
		arr[i] = read();f[i] = f[i-1];
		if(t[arr[i]] && t[arr[i]] != i-1) (f[i] += f[t[arr[i]]])%=P;
		t[arr[i]] = i;
	}
	printf("%lld",f[n]);
	return 0;
}

2 The boxing of WHH

problem

每次比赛小A获胜和失败的概率都是\(\dfrac{1}{p+2}\),平局的概率是\(\dfrac{p}{p+2}\)。如果小A的获胜场数大于落败场次,且平局次数为\(k\),则能获得\(k+1\)的分数。求获得分数的期望,在模998244353的意义下。

thoughts

可以假定胜负都有1种方案,平局有\(p\)种方案,最终乘以\((p+2)^{-n}\)即可。
枚举有\(i\)次胜利或失败,有\(n-i\)场平局,此时胜利次数大于失败的方案数是\((x+x^{-1})^i\)
展开后次数>0的项系数之和,即\((x^2+1)^i\)展开后系数\(>i\)的项系数之和。
\((x^2+1)^i\)用二项式定理直接展开并计算答案,复杂度\(O(n^2)\)

solution

考虑优化计算\((x^2+1)^i\)展开后次数\(>i\)的项系数之和,记为\(t(i)\)
用二项式定理可以得到

\[t(i)=\sum_{j=0}^i[2j>i]\left( ^i_j\right)x^{2j} \]

\(i\)为奇数的时候,每个\(2j>i\)的一定对应了一个\(2(i-j)<i\),所以\(t(i)\)一定是所有系数之和的一半,即\(t(i)=2^{i-1}\)
\(i\)为偶数时,只要减去\(j=\dfrac{i}{2}\)这一项的系数,剩下的一样一一对应,\(t(i)=\dfrac{2^i-{i\choose{i/2}}}{2}\)
复杂度\(O(n)\)

code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include <iostream>
#include <queue>
using namespace std;
int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x*=10,x+=ch^48,ch=getchar();}
	return x*f;
}
typedef long long ll;
const int P = 998244353, inv2 = (P + 1) >> 1;
int add(int a, int b) {return a + b >= P ? a + b - P : a + b;}
void inc(int &a, int b) {a = add(a, b);}
void dec(int &a, int b) {a = add(a, P - b);}
int mul(int a, int b) {return 1LL * a * b % P;}
int fpow(int a, int b){
	int res = 1;
	while (b)
	{
		if (b & 1) res = mul(res, a);
		a = mul(a, a);
		b >>= 1;
	}
	return res;
}
const int N = 3e6 + 10;
int n, p, fac[N], invfac[N];
int binom(int x, int y)
{
	return mul(fac[x], mul(invfac[y], invfac[x - y]));
}
int main()
{
	n = read(), p = read();
	fac[0] = 1;
	for (int i = 1; i <= n; ++i)
		fac[i] = mul(fac[i - 1], i);
	invfac[n] = fpow(fac[n], P - 2);
	for (int i = n - 1; i >= 0; --i)
		invfac[i] = mul(invfac[i + 1], i + 1);
	int pw = fpow(p, n), ip = fpow(p, P - 2), bin = 1, ans = 0;
	for (int i = 0; i <= n; ++i)
	{
		int tmp = mul(binom(n, i), pw);
		if (i & 1)
			tmp = mul(tmp, bin);
		else
			tmp = mul(tmp, add(bin, P - binom(i, i >> 1)));
		tmp = mul(tmp, inv2);
		tmp = mul(tmp, n - i + 1);
		inc(ans, tmp);
		pw = mul(pw, ip);
		bin = add(bin, bin);
	}
	ans = mul(ans, fpow(fpow(p + 2, n), P - 2));
	write(ans);
	return 0;
}

3 The tower of WHH

problem

给定\(n\times m\)矩阵,每个位置有一个与其他位置不相同的值,考察任意\(i\times j\)的矩阵\((i\in [1,n],j\in [1,m])\),如果\(i\times j\)的矩阵有最大值和最小值\(\operatorname{Max,Min}\),且\(\operatorname{Max}-\operatorname{Min}=i\times j-1\),则可以获得\(i\times j\)的贡献。如果考察所有可能的矩阵,求最终贡献。

thoughts

10pts/30pts:枚举每个矩形,检查其中的数字是否连续。复杂度\(O(n^3m^3)\)\(O(n^2m^2)\)
40pts/60pts:当\(n=1\)是变为一维问题,

solution

code

4 The knife of WHH

problem

solution

thoughts

code

posted @ 2020-10-23 17:50  刘子闻  阅读(130)  评论(0编辑  收藏  举报