L - Lottery (二进制 乘法原理)

题意
题意大概是这样的有n(1<=n<=1e5)个不同的盒子每个盒子有两个值ai与xi,代表第i个盒子一共有xi(1<=xi<=1e9)个小球并且每个小球的价值为2^ai(0<=ai<=1e9)从这n个盒子里随意挑选小球(也可以不挑)问一共能选出多少种不同的价值。并且答案对1e9+7去模。

题解
其实拿到这题很容易就可以往二进制的方向上去想,那么二进制下怎么进位才能不影响答案呢?因为只要每位上都有数的话那么就不会导致组合的数量的损失,那么我们把这个二进制数在每位尽可能有数的情况下去尽可能的进位就行了,最后很容易可以得到一个只有0,1,2的串。又因为0222……22等于1111……10所以说只要被0隔开的数就可以看成独立的,那么每组独立的数的组合该怎么计算呢?因为每个独立组都不含0那么很容易就可以得到每个独立组的组合数的二进制就为当前串的二进制。又由于每个串之间都是相互独立的那么我们直接用乘法原理乘一下就得出答案了。
代码如下:

#include<iostream>
#include<algorithm>
#include<map>
#define ll long long
using namespace std;
const int mod=1e9+7;
const int N=3e6;
int cnt,node[N];
struct Node{
    int x1,x2;
}now[N];
int ksm(int x,int y){
    int ans=1;
    while(y){
        if(y&1) ans=(ll)ans*x%mod;
        x=(ll)x*x%mod;
        y>>=1;
    }
    return ans;
}
int main(){
    int t,n;
    int a,x,y,k,ansd;
    scanf("%d",&t);
    for(int i=1;i<=t;i++){
        map<int,int> mp;
        cnt=0;
        scanf("%d",&n);
        for(int j=1;j<=n;j++){
            scanf("%d%d",&a,&x);
            mp[a]=x;
            node[j]=a;
        }
        sort(node+1,node+1+n);
        int noww=0;
        for(int j=1;j<=n;j++){
            k=0;
            if(noww>=node[j]+k){
                continue;
            }
            while(mp[node[j]+k]>2){
                if(mp[node[j]+k]%2){
                    mp[node[j]+k+1]+=mp[node[j]+k]/2;
                    mp[node[j]+k]=1;
                    now[++cnt].x1=node[j]+k;
                    now[cnt].x2=1;
                }else{
                    mp[node[j]+k+1]+=mp[node[j]+k]/2-1;
                    mp[node[j]+k]=2;
                    now[++cnt].x1=node[j]+k;
                    now[cnt].x2=2;
                }
                noww=node[j]+k;
                k++;
            }
            if(mp[node[j]+k]==1){
                now[++cnt].x1=node[j]+k;
                now[cnt].x2=1;
            }else if(mp[node[j]+k]==2){
                now[++cnt].x1=node[j]+k;
                now[cnt].x2=2;
            }
        }
        int ans=1,son=0,ansp=0;
        for(ll j=1;j<=cnt;j++){
            if(j==1){
                son=0,ansp=0;
                if(now[j].x2==2){
                    ansp=((ll)ansp+ksm(2,son))%mod;
                }
            }else{
                if(now[j].x1!=now[j-1].x1+1){
                    ans=((ll)ans*(((ll)ksm(2,son+1)+ansp)%mod))%mod;
                    ansp=0;
                    son=0;
                    if(now[j].x2==2){
                        ansp=((ll)ansp+ksm(2,son))%mod;
                    }
                }else{
                    son++;
                    if(now[j].x2==2){
                        ansp=((ll)ansp+ksm(2,son))%mod;
                    }
                }
            }
            if(j==cnt){
                ans=(ans*(((ll)ksm(2,son+1)+ansp)%mod))%mod;
            }
        }
        printf("Case #%d: %d\n",i,ans);
    }
    return 0;
}
抽奖系统是一种常见的应用,在设计抽奖系统时,使用基于领域驱动设计(Domain-Driven Design,DDD)的四层架构可以提供更好的架构实践。 在四层架构中,首先是用户界面层(User Interface Layer),用户界面层负责向用户展示抽奖界面,并接收用户的输入请求。用户界面层可以采用Web页面、移动应用等形式实现。通过使用领域驱动设计,用户界面层可以更加贴近用户需求,提供更好的用户体验。 接下来是应用层(Application Layer),应用层是整个抽奖系统的核心。应用层负责处理用户请求,协调各个领域对象之间的交互,并调用相应的领域服务和聚合根进行业务逻辑的处理。应用层在领域驱动设计中起到了承上启下的作用,通过定义和实现各种用例和操作,实现了系统的功能。 在领域层(Domain Layer)中,定义了抽奖系统中的核心业务逻辑。领域层包含了各种实体、值对象、聚合根等领域对象,通过这些领域对象的交互实现了系统的业务流程。在抽奖系统中,可以定义抽奖活动、参与者、奖品等领域对象,并在领域层中定义它们的行为和属性,从而满足系统的各项业务需求。 最后是基础设施层(Infrastructure Layer),基础设施层提供了抽奖系统运行所需的各种支持服务,包括数据库、缓存、消息队列等。在抽奖系统中,基础设施层可以提供参与者信息的持久化存储、抽奖结果的发送等功能。通过将基础设施逻辑与领域逻辑相分离,可以提高系统的可维护性和可扩展性。 综上所述,基于领域驱动设计的四层架构可以有效地设计和实现抽奖系统。通过将系统的核心业务逻辑与界面、应用和基础设施进行分离,可以实现系统的高内聚、低耦合,提供更好的扩展性和可维护性。同时,领域驱动设计还能够更好地满足用户需求,提供更好的用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值