题解 P3275 【[SCOI2011]糖果】

P3275 [SCOI2011]糖果

题目大意:

求满足 \(k\) 个不等关系的最小正整数解的和。

solution:

这种不等式关系,考虑用差分约束求解。
我们逐一击破每个操作:
\(c_i\) 为编号为 \(i\) 的小朋友的糖果数。

  1. \(c_a=c_b \longrightarrow c_a \geq c_b+0\)\(c_a \geq c_b+0\)
  2. $c_a \leq c_b \longrightarrow c_b \geq c_a+1 $。
  3. \(c_a \geq c_b \longrightarrow c_a \geq c_b+0\)
  4. \(c_a > c_b \longrightarrow c_a \geq c_b+1\)
  5. \(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;
}

End

posted @ 2021-07-29 20:05  Mr_think  阅读(31)  评论(0)    收藏  举报