【差分约束】账本核算

一本通4.2
任意门

题目:

小D接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的。账本上记录了n个月以来的收入情况,其中第i个月的收入额为Ai(i=1,2,3,…,n−1,n)。当 Ai大于0时表示这个月盈利Ai元,当 Ai小于0时表示这个月亏损Ai元。所谓一段时间内的总收入,就是这段时间内每个月的收入额的总和。小D的任务是秘密进行的,每次查看账本时她都只能看某段时间内账本上记录的收入情况,并且她只能记住这段时间内的总收入。现在,小D总共查看了m次账本,当然也就记住了m段时间内的总收入,你的任务是根据记住的这些信息来判断账本是不是假的。

题解:

明显 维护前缀和
(刚开始我没想到)
转换成数学语言:
s i − s j − 1 = c s_i-s_{j-1}=c sisj1=c
再转成三角不等式:
s i ≥ s j − 1 + c s_i\geq s_{j-1}+c sisj1+c
s j − 1 ≥ s i − c s_{j-1}\geq s_i-c sj1sic

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10,M=5e5+10,INF=1e9;
int S,n,m;
int head[N],nex[M],to[M],val[M],tot;
void build(int u,int v,int w){tot++;nex[tot]=head[u];to[tot]=v;val[tot]=w;head[u]=tot;}
int vis[N],dis[N];
bool dfs(int u)
{
	//printf("->%d",u);
	vis[u]=1;
	for(int i=head[u];i;i=nex[i])
	{
		int v=to[i];
		if(dis[v]<dis[u]+val[i])
		{
			dis[v]=dis[u]+val[i];
			if(vis[v])return 0;
			if(!dfs(v))return 0;
		}//printf("\n");
	}vis[u]=0;return 1;
}
void init()
{
	memset(head,0,sizeof(head));
	memset(nex,0,sizeof(nex));
	memset(val,0,sizeof(val));
	memset(to,0,sizeof(to));tot=0;	
	for(int i=0;i<=n;i++)dis[i]=-INF,vis[i]=0;
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);S=n+1;
		init();dis[S]=0;vis[S]=0;
		for(int u,v,w,i=1;i<=m;i++)
		{
			scanf("%d%d%d",&u,&v,&w);
			u--;
			build(u,v,w),build(v,u,-w);
		}
		for(int i=0;i<=n;i++)build(S,i,0);
		//
		if(!dfs(S))printf("false\n");
		else	   printf("true\n");
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值