码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ_1202_狡猾的商人

时间:2016-04-25 19:11:33      阅读:154      评论:0      收藏:0      [点我收藏+]

标签:

描述


 

 

http://www.lydsy.com/JudgeOnline/problem.php?id=1202

n 个月的账单,共 m 组数据,每一组数据包括 x , y , t ,表示从 x 月到 y 月总收益是 t .问账单前后是否矛盾.

 

分析


 

并查集+前缀和.

s[i] 表示从 i 所在集合的根到 i 的总收益.将不矛盾并已经有关联的数据放在一个集合里.

对于一组新数据:

1.如果 x 与 y 在一个集合里,就判断 s [ y ] - s [ x ] 是否等于所给值 w.

2.如果 x 与 y 不在一个集合里,则 s [ find(x) ] = s [ y ] - w -s [ x ] (可以画图判断).

 

注意:

1.我的解法是认为从 x 到 y 是 t ,也就是用 y 减去 x .反过来其实也正确.对于一个成立的账单,将所有 x - y = t 变为 y - x = t ,也就是变为了 x - y = -t ,即将所有的差值变为了原来的相反数.原来任意的月份 a , b , c ,满足 a - c = (a - b ) + ( b - c ).现在这些差值都变为了原来的相反数,相当于在等号两边同乘了-1,结果仍成立.

2.从 x 月到 y 月共收益 t 的意思是前 y 个月的收益 - 前( x - 1 )个月的收益 = t.所以要有 " x--; "的语句.

 

ps.神奇的getnum()函数还有内联,确实比之前跑得快了许多,斯国一.

 

#include<cstdio>
#include<cstring>
#include<set>
#include<algorithm>
using namespace std;

const int maxn=105,maxm=100005;
int n,m;
int a[maxn],c[maxn],f[maxm];

void solve()
{
    memset(f,-1,sizeof(f));
    f[0]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=m;j++)
        {
            if(f[j]>=0)
            {
                f[j]=c[i];
            }
            else if(a[i]<=j)
            {
                f[j]=f[j-a[i]]-1;
            }    
        }
    }
    int ans=count_if(f+1,f+m+1,bind1st(less_equal<int>(),0));//统计满足f[j]>=0的个数
    printf("%d\n",ans);
}    

void init()
{
    while(scanf("%d%d",&n,&m)==2&&(n!=0||m!=0))
    {
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++) scanf("%d",&c[i]);
        solve();
    }
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("coin.in","r",stdin);
    freopen("coin.out","w",stdout);
#endif
    init();
#ifndef ONLINE_JUDEG
    fclose(stdin);
    fclose(stdout);
    system("coin.out");
#endif
    return 0;
}

 

BZOJ_1202_狡猾的商人

标签:

原文地址:http://www.cnblogs.com/Sunnie69/p/5431851.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!