题解 [AGC013E] Placing Squares

传送门

什么神仙玩意……

猜测可以用组合数学求出无限制时的方案数
那么可以容斥

\[ans=\sum\limits_s(-1)^{|s|}f(至少在 s 中为 1 的位置断开) \]

然后尝试优化这个东西
\(f_i\) 为在 \(i\) 处断开的所有方案的带容斥系数的权值之和
转移

\[f_i\sum\limits_{j<i}-g_{i, j}\times f_j \]

猜测转移可以拆组合数+数据结构优化
应该可以做到 \(O(n\log n)\)


然后忘掉刚才胡的东西吧
这个东西不能用组合数求
因为是在序列上划分,每个段的贡献是 \(len^2\)
那么可以看成是要在每个段内放两个颜色不同的球(可以在同一个位置上),求方案数
\(f_{i, 0/1/2}\) 为考虑到位置 \(i\),已经在 \(i\) 所在的段中放了 \(j\) 个球的方案数
转移见这里
这样处理的好处是转移不是枚举转移点而是常系数线性递推的形式了,可以矩阵快速幂优化
复杂度 \(O(m\omega^3\log n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
int x[N];
const ll mod=1e9+7;
struct matrix{
	int n, m;
	ll a[4][4];
	matrix(){n=m=0; memset(a, 0, sizeof(a));}
	matrix(int x, int y) {n=x; m=y; memset(a, 0, sizeof(a));}
	void resize(int x, int y) {n=x; m=y; memset(a, 0, sizeof(a));}
	inline ll* operator [] (int t) {return a[t];}
	inline void put() {for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<a[i][j]<<' '; cout<<endl;}cout<<endl;}
	inline matrix operator * (matrix b) {
		matrix ans(n, b.m);
		for (int i=1; i<=n; ++i)
			for (int k=1; k<=m; ++k)
				for (int j=1; j<=b.m; ++j)
					ans[i][j]=(ans[i][j]+a[i][k]*b[k][j])%mod;
		return ans;
	}
}mat, tr1, tr2, I;
inline matrix qpow(matrix a, ll b) {matrix ans=I; for (; b; a=a*a,b>>=1) if (b&1) ans=ans*a; return ans;}

signed main()
{
	n=read(); m=read();
	for (int i=1; i<=m; ++i) x[i]=read();
	mat.resize(1, 3);
	mat[1][1]=1; mat[1][2]=2; mat[1][3]=1;
	tr1.resize(3, 3);
	tr1[1][1]=1; tr1[1][2]=2; tr1[1][3]=1;
	tr1[2][1]=0; tr1[2][2]=1; tr1[2][3]=1;
	tr1[3][1]=1; tr1[3][2]=2; tr1[3][3]=2;
	tr2.resize(3, 3);
	tr2[1][1]=1; tr2[1][2]=2; tr2[1][3]=1;
	tr2[2][1]=0; tr2[2][2]=1; tr2[2][3]=1;
	tr2[3][1]=0; tr2[3][2]=0; tr2[3][3]=1;
	I.resize(3, 3);
	for (int i=1; i<=3; ++i) I[i][i]=1;
	for (int i=1; i<=m; ++i) mat=mat*qpow(tr1, x[i]-x[i-1]-1)*tr2;
	mat=mat*qpow(tr1, n-1-x[m]);
	printf("%lld\n", mat[1][3]);
	
	return 0;
}
posted @ 2022-06-02 11:43  Administrator-09  阅读(5)  评论(0编辑  收藏  举报