计数

P6146 [USACO20FEB] Help Yourself G

计数题,不能枚举子集,那就算每个线段的贡献。

\(f_i\) 表示前 \(i\) 条线段的复杂度。

线段左端点排序,对于每个线段都有选和不选两种选择,当不选这条线段,贡献就为 \(f_{i-1}\),当选这条线段,所有与这条线段不并的线段的复杂度都加一,设有 \(x\) 个不并的线段,则加一个数为 \(2^x\),因为子集有 \(2^x\)个。

\(f_i=f_{i-1}+(f_{i-1}+2^x)\)

求个数直接树状数组。

#include<bits/stdc++.h>
#define ll long long
#define int ll
#define ls p<<1
#define rs p<<1|1
#define re register 
#define pb push_back
#define pir pair<int,int> 
#define f(a,x,i) for(int i=a;i<=x;i++)
#define fr(a,x,i) for(int i=a;i>=x;i--)
#define fi first
#define se second
#define lb(x) (x&-x)
using namespace std;
const int N=3e5+10;
const int M=5e6+10;
//const int mod=998244353;
const int mod=1e9+7;
const int INF=1e18+7;
mt19937 rnd(time(nullptr));

int n;

struct ss{
	int l,r;
}a[N];

bool cmp(ss g,ss h){
	return g.l<h.l;
}

int t[N];

void update(int x,int k){
	while(x<=N-10){
		t[x]+=k;
		x+=lb(x);
	}
}

int f[N];

int query(int x){
	int sum=0;
	while(x){
		sum+=t[x];
		sum%=mod;
		x-=lb(x);
	} 
	return sum;
}

int qpow(int x,int k){
	int sum=1;
	while(k){
		if(k&1){
			sum*=x;
			sum%=mod;
		}
		x*=x;
		x%=mod;
		k>>=1;
	}
	return sum;
}

void solve(){
	cin>>n;
	
	for(int i=1;i<=n;i++){
		cin>>a[i].l>>a[i].r;
	}
	
	sort(a+1,a+1+n,cmp);
	
	for(int i=1;i<=n;i++){
		f[i]=(f[i-1]*2%mod+qpow(2,query(a[i].l-1)))%mod;
		update(a[i].r,1);
	}
	cout<<f[n];
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(nullptr);
	solve();
    return 0;
}

P6008 [USACO20JAN] Cave Paintings P

想到最短路看是否可达,看了提示知道可以并查集维护,但是不会计数,写假了。

从低高度到高度,计算联通块数量,首先每个连通块数量方案数都有不选一种,当前高度及以下的全部盛满,方案数加一,因为只有盛满这个选择。

当两个连通块可合并时,相乘,再加上这个高度盛满的方案数1.

#include<bits/stdc++.h>
#define ll long long
#define int ll
#define ls p<<1
#define rs p<<1|1
#define re register 
#define pb push_back
#define pir pair<int,int> 
#define f(a,x,i) for(int i=a;i<=x;i++)
#define fr(a,x,i) for(int i=a;i>=x;i--)
#define fi first
#define se second
#define lb(x) (x&-x)
using namespace std;
const int N=1e6+10;
const int M=5e6+10;
//const int mod=998244353;
const int mod=1e9+7;
const int INF=1e18+7;
mt19937 rnd(time(nullptr));

int mp[1005][1005];

int n,m;

int fa[N];
int f[N];
bool vis[N];
int go[4][4]={{1,0},{0,1}};

int find(int x){
	return (fa[x]==x)?x:fa[x]=find(fa[x]);
}

int get(int x,int y){
	return (x-1)*m+y;
}

void solve(){
	cin>>n>>m;
	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			char c;
			cin>>c;
			mp[i][j]=(c=='#');
			int id=get(i,j);
			fa[id]=id;
			f[id]=1;
		}
	}	
	int ans=1;
	for(int i=n-1;i>=2;i--){
		for(int j=2;j<=m-1;j++){
			if(mp[i][j]) continue;
			for(int k=0;k<2;k++){
				int nx=i+go[k][0],ny=j+go[k][1];
				if(mp[nx][ny]) continue;
				int id=get(i,j);
				int u=find(id),v=find(get(nx,ny));
				
				if(u!=v){
					fa[u]=v;
					f[v]*=f[u];
					f[v]%=mod;	
				}
			}
		}	
		
		for(int j=2;j<=m-1;j++){
			if(mp[i][j]) continue;
			int x=find(get(i,j));
			if(vis[x]) continue;
			vis[x]=1;
			f[x]=(f[x]+1)%mod;
		}
		
		for(int j=2;j<=m-1;j++){
			if(mp[i][j]) continue;
			int x=find(get(i,j));
			vis[x]=0;
		}
	}
	
	for(int i=n-1;i>=2;i--){
		for(int j=2;j<=m-1;j++){
			if(mp[i][j]) continue;
			if(fa[get(i,j)]==get(i,j)){
				ans=(ans*f[get(i,j)])%mod;
			}
		}	
	}
	
	cout<<ans;
}



signed main(){
//    freopen("interval4.in","r",stdin);
//    freopen("a.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(nullptr);   
		solve();
    return 0;
}

P4071 [SDOI2016] 排列计数

\(C_{n,m}\) 好想到,剩下的数可以递推求得

#include<bits/stdc++.h>
#define ll long long
#define int ll
#define ls p<<1
#define rs p<<1|1
#define re register 
#define pb push_back
#define pir pair<int,int> 
#define f(a,x,i) for(int i=a;i<=x;i++)
#define fr(a,x,i) for(int i=a;i>=x;i--)
#define fi first
#define se second
#define lb(x) (x&-x)
using namespace std;
const int N=2e6+10;
const int M=5e6+10;
//const int mod=998244353;
const int mod=1e9+7;
const int INF=1e18+7;
mt19937 rnd(time(nullptr));

int fac[N];
int inv[N]; 


int choose(int a,int b){
	return ((fac[a]*inv[b])%mod*inv[a-b])%mod;
}

int quick_pow(int x,int k){
	int base=x%mod;
	int sum=1;
	while(k){
		if(k&1){
			sum=(sum*base)%mod;
		}
		base=(base*base)%mod;
		k>>=1;
	}
	return sum;	
}

int n,m; 

int f[N];

void solve(){
	cin>>n>>m;
	
	int z=choose(n,m);
	int k=n-m-1;
	
	cout<<(z*f[n-m])%mod<<"\n";
}



signed main(){
//    freopen("homework3.in","r",stdin);
//    freopen("a.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(nullptr); 
	fac[0]=1;
	for(int i=1;i<=N-5;i++){
		fac[i]=(fac[i-1]*i)%mod;
	}
	inv[N-5]=quick_pow(fac[N-5],mod-2);
	for(int i=N-6;i>=0;i--){
		inv[i]=(inv[i+1]*(i+1))%mod;
	}
	f[0]=1;
	f[2]=1;
	f[3]=2;
	for(int i=3;i<=N-5;i++){
		f[i]=((i-1)*(f[i-1]+f[i-2])%mod)%mod;
	}
	  
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}	
    return 0;
}
posted @ 2025-11-22 13:58  sad_lin  阅读(2)  评论(0)    收藏  举报