2019年ccpc女生赛重现赛题解I

2019年ccpc女生赛重现赛题解I
题目:
Union
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 7 Accepted Submission(s): 4

Problem Description
有三个集合 S1, S2, S3,每个集合都是 {1, 2, …, n} 的子集,现有如下条件。
|S1| + |S2| + |S3| = k
|S1| ≥ a1, |S2| ≥ a2, |S3| ≥ a3
|S1 ∪ S2| ≥ a4, |S2 ∪ S3| ≥ a5, |S1 ∪ S3| ≥ a6
|S1 ∪ S2 ∪ S3| ≥ a7
求有多少种集合 (S1, S2, S3) 的有序三元组满足上述要求,请输出答案模 1, 000, 000, 007。

Input
第一行输入两个整数 n, k。
第二行输入7个整数 a1, a2…, a7。
1 ≤ n ≤ 1, 000, 000
1 ≤ k ≤ 50
0 ≤ ai ≤ 3

Output
一行一个整数表示答案。

Sample Input

4 4
1 1 1 2 2 2 3

Sample Output

180


思路:暴力即可ac。

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+100;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9+7;
int b[8],a[8];
ll ans=0;
ll lc[maxn],inv[maxn];
int n,k;

ll fpow(ll x,ll p,ll m){
    ll res=1;
    while(p){
        if(p%2==1) res=res*x%mod;
        x=x*x%mod; p>>=1;
    }
    return res;
}

ll C(int m,int n){
    return lc[n]*inv[n-m]%mod*inv[m]%mod;
}

ll Count(){
    ll res=1; int m=n;
    for(int i=1;i<=7;++i){
        res*=C(b[i],m); m-=b[i]; res%=mod;
    }
    return res;
}

void solve(int i){
    if(i==1){
        for(b[1]=0;b[1]*3<=k;b[1]++){
            k-=b[1]*3; solve(i+1); k+=b[1]*3;
        }
    }
    else if(i<=4){
        for(b[i]=0;b[i]*2<=k;++b[i]){
            k-=b[i]*2; solve(i+1); k+=b[i]*2;
        }
    }
    else if(i==5){
        int p=b[1]+b[2]+b[3];
        for(b[5]=max(a[1]-p,0);b[5]<=k;++b[5]){
            k-=b[5]; solve(i+1); k+=b[5];
        }
    }
    else if(i==6){
        int p=a[2]-b[1]-b[3]-b[4],q=a[4]-b[1]-b[2]-b[3]-b[4]-b[5];
        for(b[6]=max(0,max(p,q));b[6]<=k;++b[6]){
            k-=b[6]; solve(i+1); k+=b[6];
        }
    }
    else if(i==7){
        b[7]=k; int p=b[1]+b[2]+b[3]+b[4];
        if(p+b[5]+b[6]+b[7]>n) return;
        if(b[2]+b[1]+b[4]+b[7]>=a[3]&&p+b[5]+b[6]+b[7]>=a[7]&&p+b[6]+b[7]>=a[5]&&p+b[5]+b[7]>=a[6]){
            //printf("%d %d %d %d %d %d %d %lld\n",b[1],b[2],b[3],b[4],b[5],b[6],b[7],Count());
            ans+=Count(); ans%=mod;
        }
    }
}

int main(){
    scanf("%d %d",&n,&k); lc[0]=inv[0]=1;
    for(int i=1;i<=n;++i){
        lc[i]=lc[i-1]*i%mod;
        inv[i]=fpow(lc[i],mod-2,mod);
    }
    for(int i=1;i<=7;++i) scanf("%d",&a[i]);
    solve(1); printf("%lld\n",ans);
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值