[AGC023C] Painting Machines
\(\text{Problem}:\)Painting Machines
\(\text{Solution}:\)
考虑现在答案是类似 \(\sum\limits_{i} f_{i}\times i\) 的形式,如何将这个 \(i\) 去掉。
\[\begin{aligned}
ans&=\sum\limits_{i=1}^{n-1}[\text{恰好 i 次操作能全部染色的排列数}]\times i\\
&=\sum\limits_{i=0}^{n-1}[\text{前 i 次操作没有全部染色的排列数}]\\
&=\sum\limits_{i=0}^{n-1}(n-1)!-[\text{前 i 次操作结束染色的排列数}]
\end{aligned}
\]
设 \(f_{i}\) 表示前 \(i\) 次操作结束染色的排列数,显然 \(f_{i}=g_{i}\cdot i!\cdot (n-i-1)!\),其中 \(g_{i}\) 表示大小为 \(i\) 的使得所有位置都被染色的操作集合数。
首先,\(1\) 和 \(n-1\) 必在集合内。还有一个限制是集合中大小相邻的两数之差小于等于 \(2\)。这可以看作从 \(2\) 或 \(3\) 开始,走 \(i-2\) 步,每步大小为 \(1\) 或 \(2\),恰好到达 \(n-1\) 的方案数。显然方案数为 \(\binom{i-2}{n-i-1}+\binom{i-2}{n-i-2}=\binom{i-1}{n-i-1}\),这也可以看作是从 \(1\) 开始以相同限制走到 \(n-1\) 的方案数。总时间复杂度 \(O(n)\)。
\(\text{Code}:\)
#include <bits/stdc++.h>
//#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=1000010, Mod=1e9+7;
inline int read()
{
int s=0, w=1; ri char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
return s*w;
}
int n,fac[N+5],inv[N+5],ans;
inline int ksc(int x,int p) { int res=1; for(;p;p>>=1, x=1ll*x*x%Mod) if(p&1) res=1ll*res*x%Mod; return res; }
inline int C(int x,int y) { if(x<y||x<0||y<0) return 0; return 1ll*fac[x]*inv[x-y]%Mod*inv[y]%Mod; }
signed main()
{
n=read();
if(n<=2) return puts("1")&0;
fac[0]=1;
for(ri int i=1;i<=N;i++) fac[i]=1ll*fac[i-1]*i%Mod;
inv[N]=ksc(fac[N],Mod-2);
for(ri int i=N;i;i--) inv[i-1]=1ll*inv[i]*i%Mod;
for(ri int i=1;i<n;i++)
{
ans=(ans+1ll*fac[i]*fac[n-i-1]%Mod*(C(i-2,n-i-1)+C(i-2,n-i-2))%Mod)%Mod;
}
printf("%d\n",(fac[n]-ans+Mod)%Mod);
return 0;
}
夜畔流离回,暗叹永无殿。
独隐万花翠,空寂亦难迁。
千秋孰能为,明灭常久见。
但得心未碎,踏遍九重天。