A.
每次关门后找到最近的
xa
x
a
以及
ty
t
y
。
若
ty<xa
t
y
<
x
a
,直接模拟即可;
否则,取
A=MIN{⌊tya⌋,n}
A
=
M
I
N
{
⌊
t
y
a
⌋
,
n
}
,计算从
xa
x
a
开始,不断地开关门直到最后一次关门的时间不小于
Aa
A
a
的次数。容易计算这个次数为
⌈A−x+1⌊da⌋+1⌉
⌈
A
−
x
+
1
⌊
d
a
⌋
+
1
⌉
,之后直接模拟能取多少个
t
t
即可。
总复杂度为。
#include<functional>
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<cmath>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
//
typedef long long ll;
const int up=1e5;ll ar[up+10];
void cl(){
ll i,j,k,t,z,n,m,a,d,_a,_b,r[2];scanf("%I64d %I64d %I64d %I64d",&n,&m,&a,&d);
for(i=0;i<m;scanf("%I64d",&ar[i++]));
for(clr(r),k=0,t=d/a+1;r[0]<n||r[1]<m;){
if(r[0]>=n){for(++k,i=r[1];r[1]<m&&ar[r[1]]-ar[i]<=d;++r[1]);}
else if(r[1]>=m){k+=(n-r[0])/t+((n-r[0])%t?1:0);break;}
else{
_a=(r[0]+1)*a,_b=ar[r[1]];
if(_b<=_a){
for(++k;r[1]<m&&ar[r[1]]-_b<=d;++r[1]);
for(;r[0]<n&&(r[0]+1)*a-_b<=d;++r[0]);
}
else{
j=min(n,_b/a);z=(j-r[0])/t+((j-r[0])%t?1:0);k+=z,r[0]+=z*t;
for(_a=(r[0]-t+1)*a;r[1]<m&&ar[r[1]]-_a<=d;++r[1]);
}
}
}
printf("%I64d\n",k);
};
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
cl();
return 0;
};
B.
显然的,若要有解,这个有向图必须是一个DAG图。
对每个节点
v
v
,其都有一个合法的取值区间。很容易由
v
v
到出度为0的点及入度为0的点的最长距离得到这个区间。
为了方便,我们可以将他们转换为递推关系:。
对于已经给定了权值
wgv
w
g
v
的节点
v
v
,那么其合法区间为。
容易发现对于任意父子节点,
lfather>lchild,rfather>rchild
l
f
a
t
h
e
r
>
l
c
h
i
l
d
,
r
f
a
t
h
e
r
>
r
c
h
i
l
d
。故在子节点的合法区间中任意地取值并不会影响父节点在更新
l
l
之后的合法性,因为最终其必然满足。
考虑如何在这些区间中取值,使得最终取值能够占满
[1,k]
[
1
,
k
]
。我们将
r
r
值从小到大进行处理,在相同时,将
l
l
从小到大进行处理,这同时使得我们必然先处理子节点,后处理父节点。
对于一个区间,我们找到最小的
x
x
使其满足:
考虑区间
[li,x)
[
l
i
,
x
)
,显然这段区间对结果已经不再有任何帮助,我们直接将其消去,那么对于其他所有最小可取值为
x
x
的区间,有
li=lj=x,ri≤rj
l
i
=
l
j
=
x
,
r
i
≤
r
j
,显然,此时我们应当取
x
x
值获得最优解。而对于其他最小可取值小于的区间
j
j
,在其中取得值必然不会比最优解更优,因为我们完全可以在
i
i
中取得值,而在
j
j
取得另一个新的值,最小可取值大于的区间同理。
故此时我们应当直接取
x
x
作为该节点的值,对于不存在的节点,随意赋一个
[li,ri]
[
l
i
,
r
i
]
中的值即可。
故 O(n) O ( n ) 求出节点的合法区间之后,按拓扑序将节点插入优先队列处理即可。总复杂度 O(nlogn) O ( n l o g n ) 。
#include<functional>
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<cmath>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
#include<queue>
#include<set>
//
typedef long long ll;
const int up=200000;
struct eg{int u,v,nx;}gp[(up<<1)+10];int cnt,hd[(up<<1)+10],dl[up+10],dr[up+10],n,m,dk,bd[up+10],wg[up+10],in[up+10],ou[up+10],tmp[up+10];
inline void psh(int u,int v){++cnt;gp[cnt].v=v,gp[cnt].u=u,gp[cnt].nx=hd[u],hd[u]=cnt;};
struct ti{int a;ti(int A=0):a(A){};
friend bool operator<(const ti&,const ti&);friend bool operator>(const ti&,const ti&);friend bool operator==(const ti&,const ti&);
};
bool operator<(const ti&a,const ti&b){return dr[a.a]==dr[b.a]?dl[a.a]<dl[b.a]:dr[a.a]<dr[b.a];};
bool operator>(const ti&a,const ti&b){return dr[a.a]==dr[b.a]?dl[a.a]>dl[b.a]:dr[a.a]>dr[b.a];};
bool operator==(const ti&a,const ti&b){return dl[a.a]==dl[b.a]&&dr[a.a]==dr[b.a];};
bool dfq(){
int i,j;for(i=1;i<=n;++i)tmp[i]=ou[i];queue<int>qe;for(clr(bd),i=1;i<=n;++i)if(!tmp[i])qe.push(i);
for(;!qe.empty();){
int v=qe.front();qe.pop();bd[v]=1;for(i=hd[v+n];i;i=gp[i].nx){
--tmp[gp[i].v];if(!tmp[gp[i].v])qe.push(gp[i].v);
}
}
for(i=1;i<=n;++i)if(!bd[i])return 0;
return 1;
};
bool dfx(int v){
int i,j;bd[v]=1;for(dl[v]=0,i=hd[v];i;i=gp[i].nx){
if(!bd[gp[i].v]&&!dfx(gp[i].v))return 0;
dl[v]=max(dl[v],dl[gp[i].v]);
}
dl[v]++;
if(dl[v]>dk)return 0;
if(wg[v]&&wg[v]<dl[v])return 0;
if(wg[v])dl[v]=wg[v];
return 1;
};
bool dfz(){
int i,j;queue<int>qe;for(clr(bd),i=1;i<=n;++i)if(!in[i])qe.push(i),dr[i]=wg[i]?wg[i]:dk;
for(;!qe.empty();){
int v=qe.front();qe.pop();if(dr[i]<dl[i])return 0;
for(i=hd[v];i;i=gp[i].nx){
if(!bd[gp[i].v]){bd[gp[i].v]=1,dr[gp[i].v]=up+233;}
--in[gp[i].v],dr[gp[i].v]=min(dr[gp[i].v],dr[v]-1);
if(!in[gp[i].v]){
if(wg[gp[i].v]&&wg[gp[i].v]>dr[gp[i].v])return 0;
if(wg[gp[i].v])dr[gp[i].v]=wg[gp[i].v];
bd[gp[i].v]=1,qe.push(gp[i].v);
}
}
}
return 1;
};
void _cl(){
int i,j,rs,d,k;priority_queue<ti,vector<ti>,greater<ti> >qe;for(i=1;i<=n;++i)if(!ou[i])qe.push(ti(i));
set<int>st;for(i=1;i<=dk;st.insert(i++));
for(rs=1;!qe.empty();){
int v=qe.top().a;qe.pop();set<int>::iterator zt=st.lower_bound(dl[v]);
if(zt==st.end()||*zt>dr[v])dl[v]=dr[v];
else
dl[v]=*zt,st.erase(zt);
for(i=hd[v+n];i;i=gp[i].nx){
dl[gp[i].v]=max(dl[gp[i].v],dl[v]+1);
--ou[gp[i].v];if(!ou[gp[i].v])qe.push(gp[i].v);
}
}
if(!st.empty())printf("-1\n");
else{
for(printf("%d",dl[1]),i=2;i<=n;printf(" %d",dl[i++]));putchar('\n');
}
};
void cl(){
int i,j,k,a,b;bool fg=1;scanf("%d %d %d",&n,&m,&dk);
for(cnt=0,clr(hd),i=1;i<=n;scanf("%d",&wg[i++]));
for(i=0;i<m;++i){scanf("%d %d",&a,&b);psh(a,b);psh(b+n,a);++in[b],++ou[a];}
if(!dfq()){printf("-1\n");return;}
for(clr(bd),i=1;i<=n;++i)if(!in[i]&&!dfx(i))fg=0;
if(!fg||!dfz()){printf("-1\n");return;}
_cl();
};
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
cl();
return 0;
};
D.
若只有一个
P
P
点,直接计算即可。
考虑二分最短时间,那么问题变成了是否能够为所有的
P
P
点选取中的一个,使得所有的区间覆盖所有的
∗
∗
点。
设表示前
i
i
个点能覆盖区间
[1,f(i)]
[
1
,
f
(
i
)
]
中的所有
∗
∗
点。在转移时,两个区间相交的情况较为特殊,但可以发现,若两个点产生的区间相交,那么前
Pi−2
P
i
−
2
个点必须覆盖一个完整的前缀中所有的
∗
∗
点,否则之后的点无法再覆盖到这些空缺。
故直接转移即可,总复杂度。
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<cmath>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
#include<set>
//
typedef long long ll;
const int up=1e6;
int n,dr[up+10],pr[up+10],dp[up+10],pn;char cz[up+10];
inline int _sg(int l,int r){return l<=r?dr[r]-dr[l-1]:0;};
bool _cl(int p){
int i,j,k;dp[0]=0;if(_sg(max(1,pr[0]-p),pr[0])==_sg(1,pr[0]))dp[0]=pr[0];
if(_sg(pr[0],min(n,pr[0]+p))==_sg(1,min(n,pr[0]+p)))dp[0]=min(pr[0]+p,n);
for(i=1;i<pn;++i){
dp[i]=dp[i-1];if(pr[i]-p<=dp[i-1]||!_sg(dp[i-1]+1,pr[i]-p-1))dp[i]=max(dp[i],pr[i]);
if(pr[i]<=dp[i-1]||!_sg(dp[i-1]+1,pr[i]-1))dp[i]=min(n,pr[i]+p);
if(pr[i]<=pr[i-1]+p&&(max(1,pr[i]-p)<=(i-2>=0?(!dp[i-2]?1:dp[i-2]):1)||!_sg(i-2>=0?dp[i-2]+1:1,pr[i]-p-1)))dp[i]=max(dp[i],min(n,pr[i-1]+p));
}
return !_sg(dp[pn-1]+1,n);
};
void cl(){
int i,j,k,d,b,e,t;scanf("%d",&n);scanf("%s",cz+1);
for(i=1,j=0;i<=n;++i)if(cz[i]=='P')++j;
if(j==1){
for(j=0,i=1;cz[i]!='P';++i)if(cz[i]=='*')++j;
for(t=i,k=0;i<=n;++i)if(cz[i]=='*')++k;
for(b=1;cz[b]!='*';++b);
for(e=n;cz[e]!='*';--e);
if(j<k){
printf("%d %d\n",k,e-t);
}
else if(k<j){
printf("%d %d\n",j,t-b);
}
else{
printf("%d %d\n",k,min(e-t,t-b));
}
}
else{
for(dr[0]=0,i=1;i<=n;++i)dr[i]=dr[i-1]+(cz[i]=='*'?1:0);
for(pn=0,i=1;i<=n;++i)if(cz[i]=='P')pr[pn++]=i;
for(b=0,e=n;b<=e;){
t=(b+e)>>1;if(_cl(t))d=t,e=t-1;
else
b=t+1;
}
for(j=0,i=1;i<=n;++i)if(cz[i]=='*')++j;
printf("%d %d\n",j,d);
}
};
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
cl();
return 0;
};
K.
采取如下方式得到
[l,r]
[
l
,
r
]
的最优解:
将区间
[l,r]
[
l
,
r
]
所有值加1,寻找
[l+1,r−1]
[
l
+
1
,
r
−
1
]
中所有不能再加的点
p
p
,即该点的值等于,继续对区间
[l+1,p1−1],[p1+1,p2−1]...
[
l
+
1
,
p
1
−
1
]
,
[
p
1
+
1
,
p
2
−
1
]
.
.
.
进行相同操作。
因为
∑⌊r−l+12⌋i=0r−l+1−2i
∑
i
=
0
⌊
r
−
l
+
1
2
⌋
r
−
l
+
1
−
2
i
必然是区间
[l,r]
[
l
,
r
]
所能得到的最优解,故上述方法可以得到最优解。
考虑如何实现这个过程,可以发现,当这个过程结束时,这个序列由递增递减交替的序列组成,而递增的起点与递减的终点都是某些点可取的最大值,即
si+gi
s
i
+
g
i
。故我们可以先从前往后构造出递增的段,然后再从后往前修复递减的段,即可得到最终的结果。总复杂度为
O(n)
O
(
n
)
。
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<cmath>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
#include<set>
//
typedef long long ll;
const int up=200000;int ar[up+10],br[up+10];
void cl(){
int i,j,k,d,t,a,b,n;scanf("%d",&n);for(i=1;i<=n;++i){
scanf("%d %d",&ar[i],&br[i]);br[i]+=ar[i];
}
for(i=2;i<=n;++i)br[i]=min(br[i-1]+1,br[i]);
for(i=n-1;i;--i)br[i]=min(br[i+1]+1,br[i]);
bool fg=1;for(i=1;i<=n;++i)if(br[i]<ar[i])fg=0;
for(i=2;i<=n;++i)if(abs(br[i]-br[i-1])>1)fg=0;
ll rs=0;for(i=1;i<=n;++i)rs+=br[i]-ar[i];
if(!fg)printf("-1\n");
else{
for(printf("%I64d\n",rs),printf("%d",br[1]),i=2;i<=n;printf(" %d",br[i++]));putchar('\n');
}
};
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
cl();
return 0;
};