CF 283C 坑死我了,半夜终于刷过,报告来了

CF283 C Coin Troubles

http://www.codeforces.com/problemset/problem/283/C

n中不同的硬币,但是他们的面值可能相同(其实无影响),有q个限制,某一种的数量要严格大于另外某一种。现在要凑成t面值,问有多少中方法,结果mod  1e9+7

首先应该想到没有q个限制的时候,是背包问题,可惜我这个背包我本来不会,后来看也没看懂,不知道是背包九讲中的哪一个。后来自己想了一下,相出了一个办法,和别人的代码一比较,发现是一样的,其实我想的办法就是背包的思路。分别用每一种硬币去更新凑成新面值的方案数,详情见代码。

问题是怎么把q个限制搞掉。

比如面值为a:1b2a要多余b,我们可以把b的值变成a+b=3,每次用一个b,就相当于ab一起用,这样就能保证a的数量永远大于等于b,那么题目要求严格大于,我们只需要在t里面减去一个a就可以了。这是两个硬币的关系,可以推到n个连续的关系上。

需要注意的是这些关系可能存在环,这样必然不能。

我是用双向链表写的dfs,比如有a>b>c>d ,那么深搜这条链,变成aa+ba+b+ca+b+c+d,然后t减去3*a+2*b+c,这里错了好久,在减的时候超过了int的下限,变成了正的,导致后面背包越界了,只要有一瞬间t<0了,答案就是0我就是被这里坑的!!!

贴代码

#include "iostream"
#include "cstdio"
#include "cstring"
#include "cmath"
#include "stdlib.h"
#include "algorithm"
using namespace std;

int flag=1,n,q,t ;
int f[100010];
typedef struct node
{
    int val,from,to,vis;
} NODE;

NODE point[310];

void dfs(int x)
{
    point[x].vis=1;
    if(point[x].to==0)
        return;
    point[point[x].to].val+=point[x].val;
    dfs(point[x].to);
    t-=point[x].val;
    if(t<0)
    flag=0;//就是这里坑了我一晚上,坑到晚上12点,终于在电脑没电前一小会AC了
}

int main()
{
    freopen("in.txt","r",stdin);
    int x,y;
    scanf("%d %d %d",&n,&q,&t);
    memset(f,0,sizeof(f));
    f[0]=1;
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&point[i].val);
        point[i].from=point[i].to=point[i].vis=0;
    }
    for(int i=0; i<q; i++)
    {
        scanf("%d %d",&x,&y);
        point[x].to=y;
        point[y].from=x;
    }
    for(int i=1; i<=n; i++)
        if(point[i].from==0)
            dfs(i);
    if(flag==0)
    {
        printf("0\n");
        return 0;
    }
    for(int i=1; i<=n; i++)
        if(point[i].vis==0)
        {
            printf("0\n");
            return 0;
        }
    for(int i=1; i<=n; i++)
        for(int j=0; j+point[i].val<=t; j++)
        {
            int tar=j+point[i].val;
            int ftar=f[tar];
            f[tar]=(f[tar]+f[j])%1000000007;
        }

    printf("%d\n",f[t]);
    return 0;
}

水平有限,众神轻喷。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值