UESTC 1646 穷且益坚, 不坠青云之志。 差分约束、Fellman-ford

穷且益坚, 不坠青云之志。

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"


否则输出"Yes",并在第二行输出一个可行解,包括n个数,保证在int范围内有解。


Sample input and output

Sample Input Sample Output
4 2 2 1 2                      Yes

                                      1 0 1 0



Source

2017 UESTC Training for Graph Theory

UESTC 1646 穷且益坚, 不坠青云之志。  


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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值