1. 程式人生 > >「HNOI2005」狡猾的商人

「HNOI2005」狡猾的商人

trade pan new push n-1 pro cstring out 記錄

題目描述

刁姹接到一個任務,為稅務部門調查一位商人的賬本,看看賬本是不是偽造的。賬本上記錄了n個月以來的收入情況,其中第i 個月的收入額為Ai(i=1,2,3...n-1,n), 。當 Ai大於0時表示這個月盈利Ai 元,當 Ai小於0時表示這個月虧損Ai 元。所謂一段時間內的總收入,就是這段時間內每個月的收入額的總和。 刁姹的任務是秘密進行的,為了調查商人的賬本,她只好跑到商人那裏打工。她趁商人不在時去偷看賬本,可是她無法將賬本偷出來,每次偷看賬本時她都只能看某段時間內賬本上記錄的收入情況,並且她只能記住這段時間內的總收入。 現在,刁姹總共偷看了m次賬本,當然也就記住了m段時間內的總收入,你的任務是根據記住的這些信息來判斷賬本是不是假的。

鏈接

BZOJ 1202
luogu 2294

題解

算法1 (差分約束系統)

思路

  • l , r , s ,表示從 lr 的和是 s
  • 維護前綴和 \(sum_i=\sum\limits_{j=1}^{i}A_j\)
  • 於是可以將 l-1r 連一條 -s 的邊,rl-1 連一條 s 的邊,即保證 \(sum_r-sum_{l-1}=s\)
  • 最後跑 spfa 判斷是否有負環

代碼

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define MAXN 105 using namespace std; typedef pair <int,int> pii; typedef long long ll; int T,n,m,Q[MAXN],cnt[MAXN]; ll dis[MAXN]; bool vis[MAXN],flg; vector <pii> e[MAXN]; void spfa(int s){ int H=0,T=1; Q[1]=s,vis[s]=1,dis[s]=0; while (H!=T){ int x=Q[++H%=MAXN]; vis[x]=0
; cnt[x]++; if (cnt[x]>n){ flg=1; return; } for (int i=0;i<e[x].size();i++){ int v=e[x][i].first; if (dis[x]+e[x][i].second<dis[v]){ dis[v]=dis[x]+e[x][i].second; if (!vis[v]){ vis[v]=1; Q[++T%=MAXN]=v; } } } } } int main(){ freopen("trader.in","r",stdin); freopen("trader.out","w",stdout); scanf("%d",&T); while (T--){ memset(dis,63,sizeof(dis)); memset(vis,0,sizeof(vis)); memset(cnt,0,sizeof(cnt)); memset(Q,0,sizeof(Q)); flg=0; scanf("%d%d",&n,&m); for (int i=0;i<=n;i++) e[i].clear(); for (int i=1;i<=m;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); e[u-1].push_back(make_pair(v,-w)); e[v].push_back(make_pair(u-1,w)); } for (int i=1;i<=n;i++){ if (!cnt[i]) spfa(i); if (flg) break; } if (flg) puts("false"); else puts("true"); } return 0; }

「HNOI2005」狡猾的商人