题目链接:http://acm.uestc.edu.cn/#/problem/show/1646
题意:求一个有n个元素的数列,满足任意连续p个数的和不小于s,
任意连续q个数的和不大于t。
解法:令sum[i]表示前i项的和(0<=i<=n,sum[0]=0)
那么题目的条件可转化为:
sum[i]-sum[i-p]>=s (p<=i<=n)
sum[i]-sum[i-q]<=t (q<=i<=n)
将第一个不等式取反,得到
sum[i-p]-sum[i]<=-s(p<=i<=n)
于是问题转化为求一系列不等式的解,这是一个典型的差分约束问题。
考虑最短路径的性质,令dis[i]表示从s到i的最短路,则对于图中存在的一条边(u,v),有
dis[v]<=dis[u]+w(u,v),即dis[v]-dis[u]<=w(u,v);
类比不等式,于是可建图,i向i-p引长度为-s的边,i-q向i引长度为t的边。
然后运行bellmanford,如果存在负环,则无解,
否则所得到的最短路的值就是sum[i]的一个解。
时间复杂度:O(VE)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1010;
const int inf = 0x3f3f3f3f;
LL dis[maxn];
int head[maxn], edgecnt, n, p, q, s, t;
int cnt[maxn];
bool inq[maxn];
struct edge{
int to,w,next;
edge(){}
edge(int to, int w, int next) : to(to), w(w), next(next) {}
}E[maxn*10];
void init(){
edgecnt = 0;
memset(head, -1, sizeof(head));
}
void add(int u, int v, int w){
E[edgecnt].to = v, E[edgecnt].w = w, E[edgecnt].next = head[u], head[u] = edgecnt++;
}
bool spfa(){
queue<int>que;
for(int i=0; i<=n; i++) dis[i]=inf;
memset(inq,0,sizeof(inq));
memset(cnt,0,sizeof(cnt));
dis[0]=0;
que.push(0);
inq[0]=1;
for(int i=1; i<=n; i++){
que.push(i);
inq[i]=1;
}
while(!que.empty()){
int u = que.front();
que.pop();
inq[u] = 0;
for(int i=head[u]; ~i; i=E[i].next){
int v = E[i].to;
int w = E[i].w;
if(dis[u] + 1LL*w < dis[v]){
cnt[v]++;
dis[v] = dis[u] + 1LL*w;
if(cnt[v]>n) return false;
if(!inq[v]){
inq[v]=1;
que.push(v);
}
}
}
}
return 1;
}
int main()
{
scanf("%d %d %d %d %d", &n, &p, &q, &s, &t);
init();
for(int i=0; i<=n; i++){
if(i-p>=0) add(i,i-p,-s);
if(i-q>=0) add(i-q,i,t);
}
if(spfa()){
printf("Yes\n");
printf("%lld", dis[1]);
for(int i=2; i<=n; i++){
printf(" %lld", dis[i]-dis[i-1]);
}
printf("\n");
}
else{
printf("No\n");
}
return 0;
}