计数
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;
}

浙公网安备 33010602011771号