Codeforces Round #295 (Div. 1) C. Pluses everywhere

Codeforces Round #295 (Div. 1) C. Pluses everywhere

题目大意:

  你有一个长度为n的'0-9'串,你要在其中加入k个'+'号,每种方案就会形成一个算式,算式算出来的值记做这次方案的贡献。

  问:所有方案的贡献,对1e9+7取模。

  n,k<=1e5.

 

首先我和zzd先探讨了一会儿暴力一点的做法,唔,非常好弄的是k*n^2,枚举子串,考虑这个子串出现在了多少个方案中,然后就是枚举左边多少个'+',然后一堆组合数...啪啦啪啦...

然后觉得既然两边分的'+'号加起来的总和相等,是不是可以不用枚举呢,比如一个预处理什么的...啪啦啪啦...

好啦,感觉上面的研究不下去了...

然后又想,不是要O(n)么,感觉像是对每个字符考虑,考虑它作为个位、十位、百位...等等的贡献。

怎么算呢?似乎现在状态比刚才好一点了?...

首先是i作为这一段的开头,j作为这一段的结尾。

现在是i作为这一段的第j位...好啦...然后我还是想不到= =

ZZD就开始秒题啦...因为原题相当于在n-1的空隙中放k个隔板。

那么若i不在最后一段,那么我先强制在i+j后插一个隔板[保证i是第j位],并且强制i到i+j之间的j-1个位置不能放,同时i+j后的位置已经放了,所以还剩n-j-1个位置,k-1个隔板,即C(n-j-1,k-1)种方案。

若i在最后一段,那么我强制i到n的j-1个位置不能放,就是C(n-j,k)种方案。

好啊,发现这个东西居然和i都没有关系,那我是不是可以把i绑起来算呢?[当然i可以用来判断这个位置是不是在最后一段,也可以判断这里到底能不能作为第j位]。

于是我们可以枚举长度l。

所以在可行的位置[1...n-l+1]中,最后一位是作为最后一段,其它的值是相同的,所以就是一个前缀和*这一坨+最后一个位置的特判,就可以了。

 

[怎么线性求组合数?] <-大家都会吧?...

  不过看在我不会的份上,还是说一下吧...就是利用的是逆元的思想,C(n,r)=n!/(n-r)!/r!,那么要是预处理出所有的阶乘以及所有阶乘的逆元,每次查询就是O(1)的了...

  预处理阶乘O(n)没问题,预处理出阶乘的逆元怎么办呢?...

  机智的ZZD发现:1/(n-1)!=1/n!*n

  %%%,先算n!的逆元,然后倒过来再乘一遍就可以了。

 

[上面的描述可能和代码中的含义有小小的不同,代码中l表示的是长度len-1,所以和上面有小小不同]


#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn=100010;
const int mod=1e9+7;
typedef long long ll;

int n,k;
ll s[maxn],lv[maxn],lv1[maxn];
char num[maxn];
ll ans;

ll C(int n,int r){
    if(r>n) return 0;
    if(r==0 || n==r) return 1;
    return ((lv[n]*lv1[r])%mod*lv1[n-r])%mod;
}

ll power(ll a,int k){
    ll ans=1;
    while(k){
        if(k&1) ans=ans*a%mod;
        k>>=1;a=a*a%mod;}
    return ans;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("C.in","r",stdin);
    freopen("C.out","w",stdout);
#endif

    scanf("%d%d",&n,&k);
    scanf("%s",num+1);

    for(int i=1;i<=n;i++)
        s[i]=(s[i-1]+num[i]-'0')%mod;
    
    lv[0]=1;
    for(int i=1;i<=n;i++)
        lv[i]=lv[i-1]*i%mod;
    lv1[n]=power(lv[n],mod-2);
    for(int i=n-1;i>=1;i--)
        lv1[i]=lv1[i+1]*(i+1)%mod;

    for(int l=0;l<n;l++){
        ans=(ans+(s[n-l-1]*C(n-l-2,k-1))%mod*power(10,l))%mod;
        ans=(ans+((num[n-l]-'0')*C(n-l-1,k))%mod*power(10,l))%mod;
    }

    printf("%I64d",ans);
    return 0;
}

基于SSM框架的智能家政保洁预约系统,是一个旨在提高家政保洁服务预约效率和管理水平的平台。该系统通过集成现代信息技术,为家政公司、家政服务人员和消费者提供了一个便捷的在线预约和管理系统。 系统的主要功能包括: 1. **用户管理**:允许消费者注册、登录,并管理他们的个人资料和预约历史。 2. **家政人员管理**:家政服务人员可以注册并更新自己的个人信息、服务类别和服务时间。 3. **服务预约**:消费者可以浏览不同的家政服务选项,选择合适的服务人员,并在线预约服务。 4. **订单管理**:系统支持订单的创建、跟踪和管理,包括订单的确认、完成和评价。 5. **评价系统**:消费者可以在家政服务完成后对服务进行评价,帮助提高服务质量和透明度。 6. **后台管理**:管理员可以管理用户、家政人员信息、服务类别、预约订单以及处理用户反馈。 系统采用Java语言开发,使用MySQL数据库进行数据存储,通过B/S架构实现用户与服务的在线交互。系统设计考虑了不同用户角色的需求,包括管理员、家政服务人员和普通用户,每个角色都有相应的权限和功能。此外,系统还采用了软件组件化、精化体系结构、分离逻辑和数据等方法,以便于未来的系统升级和维护。 智能家政保洁预约系统通过提供一个集中的平台,不仅方便了消费者的预约和管理,也为家政服务人员提供了一个展示和推广自己服务的机会。同时,系统的后台管理功能为家政公司提供了强大的数据支持和决策辅助,有助于提高服务质量和管理效率。该系统的设计与实现,标志着家政保洁服务向现代化和网络化的转型,为管理决策和控制提供保障,是行业发展中的重要里程碑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值