一本通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
si−sj−1=c
再转成三角不等式:
s
i
≥
s
j
−
1
+
c
s_i\geq s_{j-1}+c
si≥sj−1+c
s
j
−
1
≥
s
i
−
c
s_{j-1}\geq s_i-c
sj−1≥si−c
#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");
}
}