https://blog.csdn.net/Bill_Yang_2016/article/details/53556021
题目描述
给定7个整数N,A0,B0,L0,A1,B1,L1,要求设计一个01串S=s1s2…si…sN,满足:
1.si=0或si=1,1<=i<=N;
2.对于S的任何连续的长度为L0的子串sjsj+1…sj+L0-1(1<=j<=N-L0+1),0的个数大于等于A0且小于等于B0;
3.对于S的任何连续的长度为L1的子串sjsj+1…sj+L1-1(1<=j<=N-L1+1),1的个数大于等于A1且小于等于B1;
例如,N=6,A0=1,B0=2,L0=3,A1=1,B1=1,L1=2,则存在一个满足上述所有条件的01串S=010101。
用 S 表示01序列的1的个数的前缀和,然后就可以利用题目所给的不等式以及前缀和本身存在的信息,写出不等式进行差分约束算法。
注意!用前缀和表示区间和的时候所使用的前缀和数组的 L 要减1 。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+110;
int n,a0,b0,l0,a1,b1,l1;
int s[maxn];
int cnt;
struct node{
int from,to,val,next;
}edge[maxn];
int head[maxn];
void add(int u,int v,int val){
edge[cnt].from = u;
edge[cnt].to = v;
edge[cnt].val = val;
edge[cnt].next = head[u];
head[u] = cnt;
cnt++;
}
int dis[maxn],vis[maxn],num[maxn];
const int inf = 0x3f3f3f3f;
bool spfa(){
for(int i=0; i<=n; i++){
dis[i] = 0;
vis[i] = 0;
dis[i] = inf;
num[i] = 0;
}
dis[0] = 0;
vis[0] = 1;
num[0]++;
queue<int> q;
q.push(0);
while(!q.empty()){
int u = q.front();
q.pop();
vis[u] = 0;
for(int i=head[u]; i; i=edge[i].next){
int v = edge[i].to;
int w = edge[i].val;
if(dis[v] - dis[u] > w){
dis[v] = dis[u] + w;
if(!vis[v]){
num[v]++;
if(num[v] >= n) return false;
q.push(v);
vis[v] = 1;
}
}
}
}
return true;
}
int main(){
int T=5;
while(T--){
cin>>n>>a0>>b0>>l0>>a1>>b1>>l1;
dis[0] = 0;
cnt = 1;
memset(edge,0,sizeof(edge));
memset(head,0,sizeof(head));
for(int i=1; i<=n; i++){
if(i+l0-1<=n){
add(i-1,i+l0-1,-(l0-b0)); //注意!这个类似前缀和
add(i+l0-1,i-1,-(-(l0-a0))); //而前缀和计算区间内容时头要减1!!
}
if(i+l1-1<=n){
add(i-1,i+l1-1,-a1);
add(i+l1-1,i-1,-(-b1));
}
add(i-1,i,0);
add(i,i-1,-(-1));
}
bool flag=spfa();
if(flag==0) cout<<"-1"<<endl;
else{
for(int i=1; i<=n; i++){
// cout<<dis[i]<<" ";
if(dis[i]<dis[i-1])
cout<<'1';
else
cout<<'0';
}
cout<<endl;
}
}
}