穷且益坚, 不坠青云之志。
Time Limit: 6000/2000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)Submit Status
求一个有n个元素的数列,满足任意连续p个数的和不小于s,任意连续q个数的和不大于t。
Input
输入包括五个数n,p,q,s,t(1≤n,p,q≤500,1≤s,t≤100000)
Output
如果不能做到,输出"No"
Sample input and output
Sample Input Sample Output4 2 2 1 2 Yes
1 0 1 0
Source
2017 UESTC Training for Graph Theory
My Solution
题意:求一个有n个元素的数列,满足任意连续p个数的和不小于s,任意连续q个数的和不大于t。
差分约束、Fellman-ford
令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)
空间复杂度 O(V + E)
#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
typedef long long LL;
typedef pair<int, LL> ii;
const int MAXN = 1e3 + 8;
const LL INF = 1e9;
vector<ii> sons[MAXN];
LL dis[MAXN];
int cnt[MAXN];
bool inque[MAXN];
queue<int> que;
//O(nlogn)
inline bool SPFA(int n, int src)
{
for(int i = 0; i <= n; i++){
dis[i] = INF;
}
memset(inque, false, sizeof inque);
memset(cnt, 0, sizeof cnt);
dis[src] = 0;
while(!que.empty()) que.pop();
que.push(src);
inque[src] = true;
for(int i = 1; i <= n; i++){
que.push(i);
inque[i] = true;
}//这样不连通也能跑Bellman-ford
LL u, v, w, sz, i;
while(!que.empty()){
u = que.front();
que.pop();
inque[u] = false;
sz = sons[u].size();
for(i = 0; i < sz; i++){
v = sons[u][i].first;
w = sons[u][i].second;
if(dis[u] + w < dis[v]){
dis[v] = dis[u] + w;
cnt[v]++;
if(cnt[v] > n) return false;
if(!inque[v]){
inque[v] = true;
que.push(v);
}
}
}
}
return true;
}
int main()
{
#ifdef LOCAL
freopen("j.txt", "r", stdin);
//freopen("j.out", "w", stdout);
int T = 1;
while(T--){
#endif // LOCAL
//ios::sync_with_stdio(false); cin.tie(0);
int n, p, q, i;
LL s, t;
scanf("%d%d%d%lld%lld", &n, &p, &q, &s, &t);
for(i = 0; i <= n; i++){
if(i - p >= 0) sons[i].push_back(ii(i-p, -s));
if(i - q >= 0) sons[i-q].push_back(ii(i, t));
}
if(!SPFA(n, 0)) puts("No");
else{
printf("Yes\n%lld", dis[1]);
for(i = 2; i <= n; i++){
printf(" %lld", dis[i] - dis[i-1]);
}
putchar('\n');
}
#ifdef LOCAL
cout << endl;
}
#endif // LOCAL
return 0;
}
Thank you!
------from ProLights