专栏文章
题解:P9221 「TAOI-1」Pentiment
P9221题解参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @minjwx3t
- 此快照首次捕获于
- 2025/12/02 03:37 3 个月前
- 此快照最后确认于
- 2025/12/02 03:37 3 个月前
大弓蛇会平等的创每一个初见 Pentiment byd 的人。
这道题也一样。
首先一眼 dp。
设 为当前处于 这个点,且下一步要往上走的方案数。
假定网格周围都是限制点。
令 为与 同一行中 左边的第一个限制,同理, 为 右边第一个限制。
转移式为
因为在这一行中只有 的点能到达 ,所以 就是下一步将要走到这些点的方案数之和。
直接 dp 肯定会炸,考虑优化。
对于第 行的一个区间 ,根据上面的式子,可以得知对于 的所有 ,它们的 应该是相等的。
然后由于 不大,所以很多的 个点一定会被分成不多的 相同的 个区间。
然后做法就多了。
可以用 ODT,动态开点线段树维护当前行的 每次用上一行去更新这一行,注意特判连续多行没有限制的情况。
这里给出使用 ODT 的代码。
CPP#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define p_q priority_queue
#define pb push_back
#define mk make_pair
#define pii pair<int,int>
#define ve vector
#define endl '\n'
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define lowbit(x) (x&(-x))
const ll mod=998244353;
int n,m,q;
ll ksm(ll a,ll y){
ll fac=1;
while(y){
if(y&1) fac=fac*a%mod;
a=a*a%mod;
y>>=1;
}
return fac;
}
struct point{
int x,y;
}a[100005];
bool cmp(point x,point y){
if(x.x==y.x) return x.y<y.y;
return x.x<y.x;
}
struct node{
int l,r;
ll v;
node(int l_,int r_,ll v_){
l=l_;
r=r_;
v=v_;
}
bool operator<(node a)const{
return l<a.l;
}
};
set<node>s;
auto split(int x){
auto t=s.lower_bound(node(x,0,0));
if(t!=s.end()&&t->l==x) return t;
t--;
if(t->r<x) return s.end();
int l=t->l,r=t->r;
ll v=t->v;
s.erase(t);
s.insert(node(l,x-1,v));
return s.insert(node(x,r,v)).fi;
}
void dp(int l,int r,bool f){
if(l>r) return ;
auto R=split(r+1),L=split(l);
ll sum=0;
for(;L!=R;L++){
sum+=(L->v)*(L->r-L->l+1)%mod;
sum%=mod;
}
R=split(r+1);
L=split(l);
s.erase(L,R);
if(f)s.insert(node(l,r,sum));
else s.insert(node(l,r,0));
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>q;
for(int i=1;i<=q;i++){
cin>>a[i].x>>a[i].y;
}
sort(a+1,a+1+q,cmp);
s.insert(node(1,m,1));
for(int i=1;i<=q;i++){
int l=i,r=i;
for(int j=i;j<=q;j++){
if(a[j].x!=a[i].x){
break;
}
r=j;
}
if(a[i-1].x+1<a[i].x){
ll sum=0;
for(auto y:s){
sum+=y.v*(y.r-y.l+1)%mod;
sum%=mod;
}
s.clear();
s.insert(node(1,m,sum*ksm(m,a[i].x-a[i-1].x-2)%mod));
}
for(int j=l;j<=r;j++){
dp(a[j].y,a[j].y,0);
}
dp(1,a[l].y-1,1);
dp(a[r].y+1,m,1);
for(int j=l+1;j<=r;j++){
dp(a[j-1].y+1,a[j].y-1,1);
}
i=r;
}
ll sum=0;
for(auto y:s){
sum+=y.v*(y.r-y.l+1)%mod;
sum%=mod;
}
sum=sum*ksm(m,n-a[q].x)%mod;
cout<<sum;
return 0;
}
至此,一锤定音。
尘埃,已然落定。
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...