题解:AT_abc371_d [ABC371D] 1D Country

题解:P5751 [NOI1999] 01串

不容易呀,终于过了。

题目大意

给定 777 个整数 N,A0,B0,L0,A1,B1,L1N , A_0 , B_0 , L_0 , A_1 , B_1 , L_1N,A0,B0,L0,A1,B1,L1,要求构造 01 串 $ S=s_1 s_2 \dots s_i \dots s_N$,满足:

  1. si=0s_i = 0si=0si=1s_i = 1si=11≤i≤N1 \leq i \leq N1iN
  2. 对于 SSS 的任何连续的长度为 L0L_0L0 的子串 sjsj+1…sj+L0−1s_j s_{j+1} \dots s_{j+L0-1}sjsj+1sj+L01(1≤j≤N−L0+11 \leq j \leq N-L_0+11jNL0+1),000 的个数 A0≤cnt0≤B0A_0\leq cnt_0 \leq B_0A0cnt0B0
  3. 对于 SSS 的任何连续的长度为 L1L_1L1 的子串 sjsj+1…sj+L1−1s_j s_{j+1} \dots s_{j+L1-1}sjsj+1sj+L11(1≤j≤N−L1+11 \leq j \leq N-L_1+11jNL1+1) ,111 的个数 A1≤cnt1≤B1A_1\leq cnt_1 \leq B_1A1cnt1B1

分析

定义有 i∈Z∩[1,n]i \in Z \cap [1,n]iZ[1,n]

记构造的 01 串 1 的前缀个数为 xi=∑j=1i(sj=1)x_i=\sum\limits_{j=1}^i(s_j=1)xi=j=1i(sj=1)

基础条件(不论 A0,B0,L0,A1,B1,L1A_0,B_0,L_0,A_1,B_1,L_1A0,B0,L0,A1,B1,L1 的大小)

由题知 x0=0x_0=0x0=0xi−xi−1≤1x_i-x_{i-1}\leq 1xixi11xi−xi−1≥0⇒xi−1−xi≤0x_i-x_{i-1}\geq 0\Rightarrow x_{i-1}-x_i\leq 0xixi10xi1xi0

关于条件一

xi+L0−x+i≥L0−B0⇒xi−xi+L0≤B0−L0x_{i+L_0}-x+i\geq L_0-B_0\Rightarrow x_i-x_{i+L_0}\leq B_0-L_0xi+L0x+iL0B0xixi+L0B0L0

xi+L0−x+i≤L0−A0x_{i+L_0}-x+i\leq L_0-A_0xi+L0x+iL0A0

关于条件二

xi+L1−x+i≥A1⇒xi−xi+L0≤−A1x_{i+L_1}-x+i\geq A_1\Rightarrow x_i-x_{i+L_0}\leq -A_1xi+L1x+iA1xixi+L0A1

xi+L1−x+i≤B1x_{i+L_1}-x+i\leq B_1xi+L1x+iB1

得到如上关系后,差分约束即可。

Code(不可以抄)

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e3+1;
vector<pair<int,int> >G[MAXN+1];
int cnt[MAXN+1],vis[MAXN+1];
long long dist[MAXN+1];
int n,a0,b0,l0,a1,b1,l1;
void SPFA(void){
	memset(dist,0x3f,sizeof dist);
	memset(vis,0,sizeof vis);
	queue<int>Q;
	Q.push(0);
	dist[0]=0;vis[0]=1;
	while(!Q.empty()){
		int F=Q.front();Q.pop();
		for(auto i:G[F]){
			int T=i.first,w=i.second;
			if(dist[T]>dist[F]+w){
				dist[T]=dist[F]+w;
				cnt[T]=cnt[F]+1;
				if(cnt[T]>=n){
					cout<<"-1\n";
					exit(0);
				}
				if(!vis[T]){
					vis[T]=1;
					Q.push(T);
				}
			}
		}
		vis[F]=false;
	}
	return;
}
int main(){
    scanf("%d%d%d%d%d%d%d",&n,&a0,&b0,&l0,&a1,&b1,&l1);
    for(int i=1;i<=n;i++){
        G[i].push_back(make_pair(i-1,0));
        G[i-1].push_back(make_pair(i,1));
        G[n+1].push_back(make_pair(0,0));
    }
    for(int i=l0;i<=n;i++){
        G[i].push_back(make_pair(i-l0,b0-l0));
        G[i-l0].push_back(make_pair(i,l0-a0));
    }
    for(int i=l1;i<=n;i++){
        G[i].push_back(make_pair(i-l1,-a1));
        G[i-l1].push_back(make_pair(i,b1));
    }
    SPFA();
    cout<<dist[n];
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值