【省选模拟】20/05/22_#define

  • 注意到如果可以不联通的话方案数为【省选模拟】20/05/22_i++_02种,即考虑前面随便连边,最后一个点存在唯一一种合法的连边方式,最后【省选模拟】20/05/22_i++_03或分治【省选模拟】20/05/22_i++_04【省选模拟】20/05/22_#define_05容斥回去即可
#include<bits/stdc++.h>
#define cs const
#define pb push_back
#define poly vector<int>
using namespace std;
cs int Mod = 1e9 + 7;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a,b); }
void Dec(int &a, int b){ a = dec(a,b); }
void Mul(int &a, int b){ a = mul(a,b); }
int ksm(int a, int b){ int as=1; for(;b;b>>=1,Mul(a,a)) if(b&1) Mul(as,a); return as; }
cs int N = 2e3 + 50;
int n, f[2][N], fc[N], ifc[N];
int C(int n, int m){ if(n<0||m<0||n<m) return 0; return mul(fc[n],mul(ifc[n-m],ifc[m])); }
void fc_init(int n){
fc[0]=fc[1]=ifc[0]=ifc[1]=1;
for(int i=2; i<=n; i++) fc[i]=mul(fc[i-1],i);
ifc[n]=ksm(fc[n],Mod-2);
for(int i=n-1; i>=2; i--) ifc[i]=mul(ifc[i+1],i+1);
}
int main(){
#ifdef FSYolanda
freopen("road.in","r",stdin);
freopen("road.out","w",stdout);
#endif
scanf("%d",&n); fc_init(n); poly F(n+1,0);
for(int i=1; i<=n; i++) F[i]=ksm(2,(i-1)*(i-2)>>1);
poly G = F;
for(int i=1; i<=n; i++){
for(int j=1; j<i; j++)
Dec(F[i],mul(C(i-1,j-1),mul(F[j],G[i-j])));
} cout<<mul(F[n],n*(n-1)>>1);
}

【省选模拟】20/05/22_#define_06

  • 考虑跑一个从左上角开始的到关键格子的左上角的最短路树,那么这些最优路径一定会包着这棵最短路树,我们将格子的交点拆出 4 个点,直接连边,考虑若最短路树(绿色)穿过了两个格点,那么两条黄色的边将会被删掉,再考虑需要围一圈的限制,我们将关键格子蓝色部分的点删掉,这样就可以保证从周围绕过去,从左上角拆出来的右上角跑到左上角拆出来的左下角即走出了回路,建出图跑最短即可
    【省选模拟】20/05/22_#define_07
    【省选模拟】20/05/22_最短路_08
    【省选模拟】20/05/22_i++_09
  • 代码暂时咕掉了

【省选模拟】20/05/22_#define_10

  • 看成一个长为【省选模拟】20/05/22_最短路_11的序列,每种颜色的球为【省选模拟】20/05/22_最短路_12个,带标号,强制标号为 1 的在最前方(除掉第一个放的),那么答案就是合法的排列数
    若不考虑第一个不除,答案即为
    【省选模拟】20/05/22_i++_13
    下面考虑第一个,首先第一个出现位置在其它球的第一个后方,我们对这个进行容斥,考虑点一个集合【省选模拟】20/05/22_#define_14在当前枚举的【省选模拟】20/05/22_i++_15后方,那么【省选模拟】20/05/22_i++_15的贡献是
    【省选模拟】20/05/22_最短路_17
    那么我们只需要【省选模拟】20/05/22_#define_18
    【省选模拟】20/05/22_#define_19
    对于限制可以回退一下背包,【省选模拟】20/05/22_i++_20,在膜拜了大神【省选模拟】20/05/22_#define_21之后即可分治【省选模拟】20/05/22_i++_04做到【省选模拟】20/05/22_#define_23
#include<bits/stdc++.h>
#define cs const
#define pb push_back
#define poly vector<int>
using namespace std;
cs int Mod = 1e9 + 7;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a,b); }
void Dec(int &a, int b){ a = dec(a,b); }
void Mul(int &a, int b){ a = mul(a,b); }
int ksm(int a, int b){ int as=1; for(;b;b>>=1,Mul(a,a)) if(b&1) Mul(as,a); return as; }
cs int N = 55, M = 1e3 + 50;
int n, m, a[N], iv[M], fc[M], ifc[M];
int dp[M];
void fc_init(int n){
fc[0]=fc[1]=ifc[0]=ifc[1]=iv[0]=iv[1]=1;
for(int i=2; i<=n; i++) iv[i]=mul(Mod-Mod/i,iv[Mod%i]);
for(int i=2; i<=n; i++) fc[i]=mul(fc[i-1],i);
ifc[n]=ksm(fc[n],Mod-2);
for(int i=n-1; i>=2; i--) ifc[i]=mul(ifc[i+1],i+1);
}
int main(){
#ifdef FSYolanda
freopen("1.in","r",stdin);
// freopen("comb.out","w",stdout);
#endif
scanf("%d",&n); int mt=1;
for(int i=1; i<=n; i++)
scanf("%d",&a[i]), m+=a[i], Mul(mt,a[i]);
fc_init(m); mt=ksm(mt,Mod-2);
Mul(mt,fc[m]); dp[0]=1;
for(int i=1,S=0; i<=n; i++){
S+=a[i]; for(int j=S; j>=a[i]; j--)
Dec(dp[j],dp[j-a[i]]);
} int ans = 0;
for(int i=1; i<=n; i++){
for(int j=a[i]; j<=m; j++)
Add(dp[j],dp[j-a[i]]); int Sum=0;
for(int j=0; j<=m; j++) Add(Sum,mul(dp[j],iv[j+a[i]]));
Add(ans, mul(a[i]*a[i],Sum));
for(int j=m; j>=a[i]; j--)
Dec(dp[j],dp[j-a[i]]);
} cout << mul(ans,mt); return 0;
}