题解 P3336 【[ZJOI2013]话旧】
首先考虑方案。
我们用
设前一个节点与当前节点坐标分别为
-
-
-
设
len=x2-x1-y1-y2 如果len< 0 只有先向上后向下一种方案 否则分别考虑前后上升或下降的四种情况。 可以发现会形成一种类似锯齿的形状,锯齿的边可以移动。先上后下本质上就是所有上升边移到左边得到的。cnt个锯齿的边的移动方案可以表示为2^{cnt}
然后考虑最大值,最大值也可以类似的转移。不存在方案时这个值被赋为
代码如下
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<set>
#include<vector>
#include<cmath>
#define PII pair<int,int>
#define pb push_back
#define ep emplace_back
#define mp make_pair
#define fi first
#define se second
//#define int long long
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){ if(c=='-') f=-1; c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return f==1?x:~x+1;
}
inline void print(int x){
if(x<0) putchar('-'),x=~x+1;
if(x>=10) print(x/10);
putchar((x%10)|48);
}
const int mod=19940417;
int n,k;
set<PII>st;
PII a[1000010];
int dp[1000010][2],mxn[1000010][2];// 0 up 1 down
int qpow(int x,int k){
if(k<=0) return 1;
int res=1;
while(k){
if(k&1) res=1ll*res*x%mod;
x=1ll*x*x%mod;
k>>=1;
}
return res;
}
void uad(int &x,int y){
x=(x+y>=mod?x+y-mod:x+y);
}
int add(int x,int y){
return x+y>=mod?x+y-mod:x+y;
}
signed main(){
n=read(),k=read();
st.insert(mp(0,0));
st.insert(mp(n,0));
for(int i=1;i<=k;++i){
int x=read(),y=read();
st.insert(mp(x,y));
}
int m=0;
for(auto i:st){
a[++m]=i;
}
memset(mxn,-0x3f,sizeof(mxn));
dp[1][1]=1;mxn[1][0]=0;
for(int i=2;i<=m;++i){
int x1=a[i-1].fi,y1=a[i-1].se;
int x2=a[i].fi,y2=a[i].se;
if(x2-x1==y2-y1){
uad(dp[i][0],dp[i-1][0]);
mxn[i][0]=max(mxn[i-1][0],y2);
if(y1==0) uad(dp[i][0],dp[i-1][1]),mxn[i][0]=max(mxn[i-1][1],y2);
}
else if(x2-x1==y1-y2){
uad(dp[i][1],dp[i-1][1]);uad(dp[i][1],dp[i-1][0]);
mxn[i][1]=max(max(mxn[i-1][1],mxn[i-1][0]),y2);
}
else{
int len=x2-x1-y1-y2;
if(len<=0){
int pre=mxn[i-1][0];
uad(dp[i][1],dp[i-1][0]);if(y1==0) uad(dp[i][1],dp[i-1][1]),pre=max(pre,mxn[i-1][1]);
if(dp[i][1])mxn[i][1]=max(pre,(x2+y2-y1-x1>>1)+y1);//x+y=x2-x1,x-y=y2-y1 x=x2+y2-y1-x1
}
if(len>=0){
if(len==0){
uad(dp[i][0],dp[i-1][0]);uad(dp[i][0],dp[i-1][1]);
mxn[i][0]=max(max(mxn[i-1][1],mxn[i-1][0]),y2);
}
else{
int t,t2;
if(dp[i-1][0]>0){
// printf("O:%d\n",i);
t=max(max(y1==0?mxn[i-1][1]:-0x3f3f3f3f,mxn[i-1][0]),(x2+y2-y1-x1>>1)+y1);
t2=max(max(y1==0?mxn[i-1][1]:-0x3f3f3f3f,mxn[i-1][0]),y1+(x2-y2-y1-x1>>1));
}
else{
// printf("i:%d\n",i);
t=max(mxn[i-1][1],(x2-x1-y1+y2>>1));//x+y=x2-x1-y1,x-y=y2
t2=max(mxn[i-1][1],len>>1);//x+y=x2-x1-y1-y2,x-y=0
}
int k=add(1ll*dp[i-1][1]*qpow(2,(len>>1)-1)%mod,1ll*dp[i-1][0]*qpow(2,len>>1)%mod);
if(y2>0) uad(dp[i][0],k),mxn[i][0]=max(t2,y2);
uad(dp[i][1],k);mxn[i][1]=max(t,y2);
}
}
}
if(!dp[i][0]) mxn[i][0]=-0x3f3f3f3f;
if(!dp[i][1]) mxn[i][1]=-0x3f3f3f3f;
// printf("i:%d,mxn:%d,%d\n",i,mxn[i][0],mxn[i][1]);
}
printf("%d %d\n",dp[m][1],mxn[m][1]);
}