洛谷P3336 [ZJOI2013]话旧 题解
题目链接:P3336 [ZJOI2013]话旧
题意:小林跟着银河队选手去了一趟宇宙比赛,耳濡目染,变得学术起来。回来后,他发现世界大变样了。比丘兽究级进化,成了凤凰兽;金先生因为发了一篇 paper,一跃成为教授,也成为了银河队选拔委员会成员。
一日,小林与金教授聊天。金教授回忆起过去的岁月,那些年他学过的电路原理。他曾经对一种三角波很感兴趣,并且进行了一些探究。小林感到很好奇,于是金教授就将课题形式化地说了一遍。
有一定义在 $[0,N]$ 的连续函数 $f(x)$,其中 $N$ 是整数,满足 $f(0)=f(N)=0$,它的所有极值点在整数处取到,且 $f(x)$ 的极小值均是 $0$。对于任意的 $0$ 到 $N-1$ 间的整数 $I$,$f(x)$ 在 $(I, I+1)$ 上是斜率为 $1$ 或 $-1$ 的一次函数。
金先生研究的是,若他知道其中 $K$ 个整点的函数值,那么:
- 有多少个函数满足条件?
- 满足条件的函数中,$f(x)$ 的最大值,最大能是多少?
小林思考了一下,便想出了很好的算法。那么作为经过多年训练的你呢?
输入格式
第一行包含两个用空格隔开的整数 $N,K$。接下来 $K$ 行,每行两个整数,表示 $x_i$ 和 $f(x_i)$。
输出格式
一行两个整数,分别对应两个问题的答案。考虑到第一问答案可能很大,你只要输出它除以 $19940417$ 的余数。
输入输出样例
输入 #1
2 0
输出 #1
1 1
输入 #2
6 9 4 2 4 2 2 0 4 2 6 0 5 1 2 0 0 0 0 0
输出 #2
1 2
说明/提示
- 对于 $10\%$ 的数据,$N \leq 10$。
- 对于 $20\%$ 的数据,$N \leq 50$。
- 对于 $30\%$ 的数据,$N \leq 100$,$K \leq 100$。
- 对于 $50\%$ 的数据,$N \leq 10^3$,$K \leq 10^3$。
- 对于 $70\%$ 的数据,$N \leq 10^5$。
- 另有 $10\%$ 的数据,$K=0$。
- 对于 $100\%$ 的数据,$0 \leq N \leq 10^9$,$0 \leq K \leq 10^6$。
题目说了极小值为 $0$ ,说明每次下降都是直接一口气到底的
从文字中可以看出题目保证了有解(不然怎么输出最大值)
考虑设计状态 $dp[i][0/1]$ 表示是需要访问到 $i$ 结点时的路径是向上还是向下的
$dp[i][1] \to dp[i+1][0]$
显然延长左右的两条路径,可得零点 $a,b$
然后在 $a,b$ 间反复横跳便可以相连了
设 $a,b$ 间的距离为 $2k$ ,则方案数为 $2^{k-1}$
如下图 $(2k=6)$
\ / \ / \/\/\/\/
观察到其形成了 $4$ 个
\/
的结构,不妨其为齿孔\ / \ /\ / \/ \/\/
注意到此时除了两侧的齿孔不可扩展以外,其余均可扩展
故方案数为 $2^2 = 4$
$dp[i][0] \to dp[i+1][0]$
不妨将 $i$ 与其向上的路径看作一个点,则又可以确定两个零点 $a,b$
而此时左侧的齿孔也可以扩展了,而右侧的仍不可,故方案数为 $2^k$
如下图 $(2k=4)$
/\ / \ / \/\/\/
扩展左侧齿孔会变成
/\ / / \ / \/\/
故方案数为 $2^2 = 4$
$dp[i][1]\to dp[i+1][1]$
与上一种情况类似,将 $i+1$ 与其向下的路径看作一个点
右侧的齿孔可以扩展,而此时左侧的不可,故方案数为 $2^k$
$dp[i][0] \to dp[i+1][1]$
考虑将 $i+1$ 与其向下的路径看作一个点
则此时左侧的齿孔可以扩展,而右侧的不可以
故方案数为 $2^k$
然而有些情况会导致 $k<0$ ,因此要特判一下
还有一些特殊的情况,比如 $i+1$ 恰好在 $i$ 的向上/下的路径上,也需要特判
然后最大值的求解,根据贪心,一定先选掉所有的上升
设有 $a$ 个上升, $b$ 个下降,则有
则最大值为
但是要注意,如果可以选择向上,一定有 $dp[i][0]\ne0$
因此对于所有的 $i$ 到 $i+1$ 的转移,都额外计算一下先走到底再上升的情况,即
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
namespace FastIO
{
#define gc() readchar()
#define pc(a) putchar(a)
#define SIZ (int)(1e6+15)
char buf1[SIZ],*p1,*p2;
char readchar()
{
if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
return p1==p2?EOF:*p1++;
}
template<typename T>void read(T &k)
{
char ch=gc();T x=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
k=x*f;
}
template<typename T>void write(T k)
{
if(k<0){k=-k;pc('-');}
static T stk[66];T top=0;
do{stk[top++]=k%10,k/=10;}while(k);
while(top){pc(stk[--top]+'0');}
}
}using namespace FastIO;
#define N (int)(1e6+15)
const int p=19940417;
int n,k,mx;
void add(int &a,int b){a=((a+b%p)%p+p)%p;}
int qpow(int a,int b)
{
int ans=1,base=a%p;
while(b)
{
if(b&1)ans=ans*base%p;
base=base*base%p;
b>>=1;
}
return ans;
}
struct node
{
int x,y;
}a[N];
bool operator<(node a,node b)
{return a.x<b.x;}
bool operator==(node a,node b)
{return a.x==b.x&&a.y==b.y;}
int dp[N][2];
signed main()
{
read(n);read(k);
for(int i=1; i<=k; i++)
read(a[i].x),read(a[i].y);
a[++k]={0,0};a[++k]={n,0};
sort(a+1,a+1+k);k=unique(a+1,a+1+k)-a-1;
dp[1][1]=1;
for(int i=1; i<k; i++)
{
int d=(a[i+1].x-a[i].x-a[i+1].y-a[i].y)>>1;
mx=max(mx,(a[i+1].x+a[i+1].y-a[i].x-a[i].y)>>1);
if(dp[i][0])mx=max(mx,(a[i+1].x+a[i+1].y-a[i].x+a[i].y)>>1);
if(a[i+1].y-a[i].y==a[i].x-a[i+1].x)
add(dp[i+1][1],dp[i][0]+dp[i][1]);
else if(a[i+1].y-a[i].y==a[i+1].x-a[i].x)
add(dp[i+1][0],dp[i][0]+(a[i].y?0:dp[i][1]));
else if(d<0)
add(dp[i+1][1],dp[i][0]);
else if(d==0)
add(dp[i+1][0],dp[i][0]+dp[i][1]),add(dp[i+1][1],dp[i][0]);
else
{
int c=qpow(2,d-1);
if(a[i+1].y)add(dp[i+1][0],(dp[i][1]+2ll*dp[i][0]%p)%p*c);
add(dp[i+1][1],(dp[i][1]+2ll*dp[i][0]%p)%p*c);
}
}
printf("%lld %lld\n",dp[k][1],mx);
return 0;
}