SPOJ16607 IE1 - Sweets

题面

传送门:


Solution

这题的想法挺妙的。

.

首先,对于这种区间求答案的问题,我们一般都可以通过类似前缀和的思想一减来消去a,即求[a,b]的答案可以转化为求[1,b]-[1,a-1]

接下来我们可以先考虑一下每个物品数量不限制的做法。我们可以把这个问题类比为放球问题:我们要在n个相同的盒子里放x个球,这个问题可以用隔板法解决,显然答案为\(C_{x+n-1}^{n-1}\)

因为我们的n特别小,而且p为合数,所以可以用分解质因数的方法来算这个组合数。

.

接下来,我们可以考虑一下如何处理多计算的答案,考虑用容斥定理来解决这个问题。

不了解容斥定理的同志可以先看一下这篇文章

我们要求的是至少有一个物品不满足要求的方案总数,即求所有不满足要求的方案的并。

根据容斥定理,这个并的值为 \(\sum有一个物品不满足要求-有两个物品不满足要求+有三个物品不满足要求-...\)

所以说,我们只需要强制某些物品先选\(m_i+1\)个,再按照上面的放球问题的公式来计算就可以得出有若干个物品不满足要求的方案数。

答案即为总方案数-不满足要求的方案数的并

时间复杂度\(O(2^n*log_{max(a,b)})\)

这个问题就被我们切掉啦ヽ( ̄▽ ̄)?

.

如果有不清楚的地方可以看一下代码。


Code

//Luogu SP16607 IE1 - Sweets
//Jan,14th,2019
//容斥原理的应用
#include<iostream>
#include<cstdio>
using namespace std;
long long read()
{
    long long x=0,f=1; char c=getchar();
    while(!isdigit(c)){if(c==‘-‘) f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-‘0‘;c=getchar();}
    return x*f;
}
const int poi=2004;
const int N=15;
int prime[6]={-1,2,3,5,7};
long long C(long long x,long long y)//x为底,y为指
{
    if(y>x) return 0;
    int cnt[6]={0};
    long long t_ans=1;
    for(long long i=x-y+1;i<=x;i++)
    {
        long long t_num=i;
        for(int j=1;j<=4;j++)
            while(t_num%prime[j]==0)
            {
                t_num/=prime[j];
                cnt[j]++;
            }
        t_ans=(t_ans*t_num)%poi;
    }
    for(long long i=1;i<=y;i++)
    {
        long long t_num=i;
        for(int j=1;j<=4;j++)
            while(t_num%prime[j]==0)
            {
                t_num/=prime[j];
                cnt[j]--;
            }
        }
    for(int i=1;i<=4;i++)
        while(cnt[i]>0)
            t_ans=(t_ans*prime[i])%poi,cnt[i]--;
    return t_ans;
}
int m[N],n,a,b;
long long t_ans2,t_x;
bool used[N];
void dfs(int now)
{
    if(now==n+1)
    {
        long long t_cnt=0,tot=0;
        for(int i=1;i<=n;i++)
            if(used[i]==true)
                t_cnt+=m[i]+1,tot++;
        if(t_cnt>t_x) return;
        long long f=(tot%2==1?-1:1);
        t_ans2+=f*C(t_x-t_cnt+n,n);
        t_ans2=(t_ans2%poi+poi)%poi;
        return;
    }
    for(int i=0;i<=1;i++)
        used[now]=i,dfs(now+1);
}
long long Calc(long long x)
{
    t_ans2=0,t_x=x;
    dfs(1);
    return t_ans2;
}
int main()
{
    n=read(),a=read(),b=read();
    for(int i=1;i<=n;i++)
        m[i]=read();

    printf("%lld",((Calc(b)-Calc(a-1))%poi+poi)%poi);
    return 0;
}

原文地址:https://www.cnblogs.com/GoldenPotato/p/10268507.html

时间: 2024-08-04 14:30:43

SPOJ16607 IE1 - Sweets的相关文章

Codeforces Round #152 (Div. 2) D. Sweets for Everyone!(二分)

大致题意:有一些商店和一些居民在一排上,某人要从起点開始对全部居民发放1kg糖果,每一个商店能够能够且仅能够买一次1kg糖果,每向前或向后走以单位须要1时间单位,求在t时间内发完所以的居民最少须要自身带多少kg糖果 思路:这样的题,明显就是二分,二分答案.然后从边界開始判可行.这题的可行还是有点难判.首先糖果手中充足,遇到一个居民就发放1kg.当糖果不充足的时候.仅仅能有两种决策,直接跑到尽头.再回来. 或者继续往前走,知道糖果数已经集够所需再回来. 来差分后的序列来说就是,当sum[i] ==

CF w1d1 C. The Party and Sweets

n boys and m girls came to the party. Each boy presented each girl some integer number of sweets (possibly zero). All boys are numbered with integers from 1 to n and all girls are numbered with integers from 1 to m. For all 1≤i≤n the minimal number o

BZOJ 3027 Sweets 生成函数,容斥

Description John得到了n罐糖果.不同的糖果罐,糖果的种类不同(即同一个糖果罐里的糖果种类是相同的,不同的糖果罐里的糖果的种类是不同的).第i个糖果罐里有 mi个糖果.John决定吃掉一些糖果,他想吃掉至少a个糖果,但不超过b个.问题是John 无法确定吃多少个糖果和每种糖果各吃几个.有多少种方法可以做这件事呢? Input 从标准输入读入每罐糖果的数量,整数a到b John能够选择的吃掉糖果的方法数(满足以上条件) Output 把结果输出到标准输出(把答案模 2004 输出)

万圣节的糖果(Halloween Sweets)

今天遇到codewars的一道题,这是链接,讲的是关于万圣节的一个题目,简单点说,就是9个包裹,一个天平,两次称的机会,怎么找出9个包裹中唯一一个较重的包裹. 像我这种年轻时候喜欢研究难题获得存在感的蠢材,觉得很开心,因为这是我为数不多还记得答案的小学题.包裹分成三堆,取两个堆一称,可以得到哪个是比较中的一堆,然后再在这个异常的堆里选择两个称,找到嫌疑犯X. 于是我开始码代码 function pick(bags, scale) { switch(scale.weigh([bags[0],bag

HTML5项目笔记7:使用HTML5 WebStorage API构建与.NET对应的会话机制

HTML5的Web Storage API,我们也称为DOMStarage API,用于在Web请求之间持久化数据.在Web Starage API 出现之前,我们都是将客户端和服务端之间的交互数据存储在远程服务器上,随着Web Starage API的出现,我们可以在客户端存储我们重复访问的交互数据,用户在打开浏览器的时候,可以快速地读取到数据,减少了用户等待,数据流量. 在Web Starage 出现之前,我们在客户端存储数据一般使用Cookie,用于客户端和服务端之间保存会话标识符,同时可

C51指针与A51汇编接口之间关系研究

最近在研究单片机C51对汇编的接口问题.char和int等都比较简单,使用寄存器或固定地地址传值都是可以的,具体可以参考keil的C51 user's guide.本篇短文主要重点讨论一下A51下如何遵循C51的接口标准来实现C51的指针.主要原因是,现在用C51的人越来越多,大家都图省事和方便.网上面有关A51的资料少得可怜,知道用汇编来实现代码优化的少之又少.本人是一直坚持用汇编写东西的.在嵌入式领域,很多东西都与硬件有关,多知道点底层东西还是有好处. 使用工具主要为keil,在window

POJ 3370 Halloween treats(抽屉原理)

Halloween treats Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 6631   Accepted: 2448   Special Judge Description Every year there is the same problem at Halloween: Each neighbour is only willing to give a certain total number of sweets

第十七章----面向对象(宠物乱斗之主后台篇)

写了挺多,脑子都炸了,眼都花了..注释以后再加吧. package com.maya.chongwu; import java.util.Date; public class Pet { private int Hp; boolean lock = true; private String name; private String name1; public int num; boolean lock1 = true; private String sex; private int age; p

msp430知识

IO口 数字输入/输出端口有下列特性:□ 每个输入/输出位都可以独立编程.□ 允许任意组合输入.输出.□ P1 和 P2 所有 8 个位都可以分别设置为中断.□ 可以独立操作输入和输出数据寄存器.□ 可以分别设置上拉或下拉电阻. 在介绍这四个I/O口时提到了一个“上拉电阻”那么上拉电阻又是一个什么东东呢?他起什么作用呢?都说了是电阻那当然就是一个电阻啦,当作为输入时,上拉电阻将其电位拉高,若输入为低电平则可提供电流源;所以如果P0口如果作为输入时,处在高阻抗状态,只有外接一个上拉电阻才能有效.