題解 P3275 【[SCOI2011]糖果】
阿新 • • 發佈:2021-07-29
P3275 [SCOI2011]糖果
題目大意:
求滿足 \(k\) 個不等關係的最小正整數解的和。
solution:
這種不等式關係,考慮用差分約束求解。
我們逐一擊破每個操作:
設 \(c_i\) 為編號為 \(i\) 的小朋友的糖果數。
- \(c_a=c_b \longrightarrow c_a \geq c_b+0\) 且 \(c_a \geq c_b+0\)。
- $c_a \leq c_b \longrightarrow c_b \geq c_a+1 $。
- \(c_a \geq c_b \longrightarrow c_a \geq c_b+0\)。
- \(c_a > c_b \longrightarrow c_a \geq c_b+1\)
- \(c_a \leq c_b \longrightarrow c_b \geq c_a+0\)。
按照差分約束連邊後跑最長路即可。
細節處理:
- 注意判斷無解情況,輸出 \(-1\)。
- 結果用 \(\text{long long }\) 儲存。
- 源點倒序連線,玄學優化。
- 操作 \(2\) 和 \(4\) 特判自己不能比自己多/少。
程式碼
#include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=2e5+5; int n,m; int hd[N],nt[N<<1],to[N<<1],ww[N<<1],cnt; inline void tian(int x,int y,int z){ to[++cnt]=y,ww[cnt]=z,nt[cnt]=hd[x],hd[x]=cnt; } int dis[N],num[N];bool vis[N]; inline bool spfa(){ queue<int> q; dis[0]=0,vis[0]=1; q.push(0); while(q.size()){ int x=q.front();q.pop(); vis[x]=0; for(int i=hd[x];i;i=nt[i]){ int y=to[i],z=ww[i]; if(dis[y]<dis[x]+z){ dis[y]=dis[x]+z; if(!vis[y]){ vis[y]=1,num[y]++; if(num[y]==n+1) return 0; q.push(y); } } } } return 1; } int main(){ scanf("%d%d",&n,&m); for(int i=n;i>=1;i--) tian(0,i,1);//玄學優化 for(int i=1,op,x,y;i<=m;i++){ scanf("%d%d%d",&op,&x,&y); if(op==1) tian(x,y,0),tian(y,x,0); else if(op==2) tian(x,y,1); else if(op==3) tian(y,x,0); else if(op==4) tian(y,x,1); else if(op==5) tian(x,y,0); if(op%2==0&&x==y) return puts("-1"),0;//特判 } if(!spfa()) return puts("-1"),0;//無解 long long ans=0; for(int i=1;i<=n;i++) ans+=dis[i];//統計答案 printf("%lld",ans); return 0; }