题解 [bzoj3456] 城市规划 & [bzoj5093] 图的价值

传送门
传送门

思路很巧妙的两个题
草稿纸在蓝书里

  • (尤其是图上连通性DP)是可以用「恰好」和「至少」之间的关系列出等量关系,进而解出其中一个的表达式的
  • 图上度数为 \(i\) 的点产生 \(a_i\) 的贡献:
    拆贡献要拆的彻底,事实上可以拆成钦定一个点满足这个条件,剩下的随便选
    不只是图,序列也可以这么干,就是说「求所有情况中包含「···」的数量」的情况都可以这样拆开
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 520010
#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;
int rev[N], bln, bct;
ll fac[N], inv[N], f[N], g[N], a[N], b[N];
const ll mod=1004535809, rt=3, phi=mod-1;
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}
inline ll C(ll n) {return n*(n-1)/2;}

void ntt(ll* a, int len, int op) {
	for (int i=0; i<len; ++i) if (i<rev[i]) swap(a[i], a[rev[i]]);
	ll w, wn, t;
	for (int i=1; i<len; i<<=1) {
		wn=qpow(rt, (op*phi/(i<<1)%phi+phi)%phi);
		for (int j=0,step=i<<1; j<len; j+=step) {
			w=1;
			for (int k=j; k<j+i; ++k,w=w*wn%mod) {
				t=w*a[k+i]%mod;
				a[k+i]=(a[k]-t)%mod;
				a[k]=(a[k]+t)%mod;
			}
		}
	}
	if (op==-1) {
		ll inv=qpow(len, mod-2);
		for (int i=0; i<len; ++i) a[i]=a[i]*inv%mod;
	}
}

void cdq(int l, int r, int bct) {
	if (l==r||!bct) {f[l]=!l?0:(qpow(2, C(l))-fac[l-1]*f[l])%mod; return ;}
	int mid=(l+r)>>1;
	cdq(l, mid, bct-1);
	// cout<<"cdq: "<<l<<' '<<r<<endl;
	for (int i=0; i<r-l; ++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bct-1));
	for (int i=l; i<mid; ++i) a[i-l]=f[i]*inv[max(i-1,0)]%mod;
	// cout<<"a: "; for (int i=l; i<mid; ++i) cout<<a[i-l]<<' '; cout<<endl;
	for (int i=mid; i<r; ++i) a[i-l]=0;
	for (int i=0; i<r-l; ++i) b[i]=g[i];
	// cout<<"b: "; for (int i=0; i<r-l; ++i) cout<<b[i]<<' '; cout<<endl;
	ntt(a, r-l, 1); ntt(b, r-l, 1);
	for (int i=0; i<r-l; ++i) a[i]=a[i]*b[i]%mod;
	ntt(a, r-l, -1);
	// cout<<"a: "; for (int i=0; i<r-l; ++i) cout<<a[i]<<' '; cout<<endl;
	for (int i=mid; i<r; ++i) f[i]=(f[i]+a[i-l])%mod;
	cdq(mid, r, bct-1);
}

signed main()
{
	n=read();
	fac[0]=fac[1]=1; inv[0]=inv[1]=1;
	for (int i=2; i<=n; ++i) fac[i]=fac[i-1]*i%mod;
	for (int i=2; i<=n; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
	for (int i=2; i<=n; ++i) inv[i]=inv[i-1]*inv[i]%mod;
	for (int i=1; i<=n; ++i) g[i]=qpow(2, C(i))*inv[i]%mod;
	for (bln=1,bct=0; bln<=n+1; bln<<=1,++bct);
	// cout<<"g: "; for (int i=0; i<=n; ++i) cout<<g[i]<<' '; cout<<endl;
	cdq(0, bln, bct);
	// cout<<"f: "; for (int i=0; i<=n; ++i) cout<<f[i]<<' '; cout<<endl;
	printf("%lld\n", (f[n]%mod+mod)%mod);

	// for (int i=1; i<=n; ++i) {
	// 	for (int j=1; j<i; ++j) f[i]=(f[i]+f[j]*inv[j-1]%mod*g[i-j])%mod;
	// 	f[i]=(qpow(2, C(i))-fac[i-1]*f[i])%mod;
	// }
	// cout<<"f: "; for (int i=0; i<=n; ++i) cout<<f[i]<<' '; cout<<endl;
	// printf("%lld\n", (f[n]%mod+mod)%mod);
	
	return 0;
}
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 800010
#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, k;
int rev[N], bln, bct;
ll f[N], g[N], decr[N], inv[N], ans;
const ll mod=998244353, rt=3, phi=mod-1;
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}

void ntt(ll* a, int len, int op) {
	for (int i=0; i<len; ++i) if (i<rev[i]) swap(a[i], a[rev[i]]);
	ll w, wn, t;
	for (int i=1; i<len; i<<=1) {
		wn=qpow(rt, (op*phi/(i<<1)+phi)%phi);
		for (int j=0,step=i<<1; j<len; j+=step) {
			w=1;
			for (int k=j; k<j+i; ++k,w=w*wn%mod) {
				t=w*a[k+i]%mod;
				a[k+i]=(a[k]-t)%mod;
				a[k]=(a[k]+t)%mod;
			}
		}
	}
	if (op==-1) {
		ll inv=qpow(len, mod-2);
		for (int i=0; i<len; ++i) a[i]=a[i]*inv%mod;
	}
}

signed main()
{
	n=read(); k=read();
	decr[0]=1; inv[0]=inv[1]=1;
	for (int i=1; i<=k; ++i) decr[i]=decr[i-1]*(n-i)%mod;
	for (int i=2; i<=k; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
	for (int i=2; i<=k; ++i) inv[i]=inv[i-1]*inv[i]%mod;
	for (int i=0; i<=k; ++i) f[i]=(i&1?-1:1)*inv[i];
	for (int i=0; i<=k; ++i) g[i]=qpow(i, k)*inv[i]%mod;
	for (bln=1; bln<=(k+1)*2; bln<<=1,++bct) ;
	for (int i=0; i<bln; ++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bct-1));
	ntt(f, bln, 1); ntt(g, bln, 1);
	for (int i=0; i<bln; ++i) f[i]=f[i]*g[i]%mod;
	ntt(f, bln, -1);
	// cout<<"f: "; for (int i=0; i<bln; ++i) cout<<(f[i]+mod)%mod<<' '; cout<<endl;
	for (int i=0; i<=k; ++i) if (n-i-1>=0) ans=(ans+f[i]*decr[i]%mod*qpow(2, n-i-1))%mod;
	printf("%lld\n", (n*ans%mod*qpow(2, 1ll*(n-1)*(n-2)/2)%mod+mod)%mod);
	
	return 0;
}
posted @ 2022-01-12 07:06  Administrator-09  阅读(6)  评论(0编辑  收藏  举报