标签:
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; }
标签:
原文地址:http://www.cnblogs.com/Sunnie69/p/5431851.html