Codeforces954F Runner's Problem矩阵优化DP

2 篇文章 0 订阅
2 篇文章 0 订阅
题目链接:http://codeforces.com/problemset/problem/954/F
F. Runner's Problem
time limit per test
4 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You are running through a rectangular field. This field can be represented as a matrix with 3 rows and m columns. (i, j) denotes a cell belonging to i-th row and j-th column.

You start in (2, 1) and have to end your path in (2, m). From the cell (i, j) you may advance to:

  • (i - 1, j + 1) — only if i > 1,
  • (i, j + 1), or
  • (i + 1, j + 1) — only if i < 3.

However, there are n obstacles blocking your path. k-th obstacle is denoted by three integers ak, lk and rk, and it forbids entering any cell (ak, j) such that lk ≤ j ≤ rk.

You have to calculate the number of different paths from (2, 1) to (2, m), and print it modulo 109 + 7.

Input

The first line contains two integers n and m (1 ≤ n ≤ 104, 3 ≤ m ≤ 1018) — the number of obstacles and the number of columns in the matrix, respectively.

Then n lines follow, each containing three integers ak, lk and rk (1 ≤ ak ≤ 3, 2 ≤ lk ≤ rk ≤ m - 1) denoting an obstacle blocking every cell (ak, j) such that lk ≤ j ≤ rk. Some cells may be blocked by multiple obstacles.

Output

Print the number of different paths from (2, 1) to (2, m), taken modulo 109 + 7. If it is impossible to get from (2, 1) to (2, m), then the number of paths is 0.

Example
Input
Copy
2 5
1 3 4
2 2 3
Output
2
翻译:
有一个3×M的田野
一开始你在(1,2)位置
如果你在(i,j)位置
在不出界的前提下,可以走到(i+1,j),(i+1,j±1)
有n段障碍,障碍不能走
询问从(1,2)到达(M,2)的方案数
n<=10^4,M<=10^18。
题解:首先可以列出很简单的转移方程,然后想到用矩阵优化,但是由于有坏点,不能走,所以需要离散化这些坏点,然后分段快速幂即可。
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef long double ld;

#define x0 x0___
#define y0 y0___
#define pb push_back
#define SZ(X) ((int)X.size())
#define mp make_pair
#define fi first
#define se second
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pli pair<ll,int>
#define pil pair<int,ll>
#define ALL(X) X.begin(),X.end()
#define RALL(X) X.rbegin(),X.rend()
#define rep(i,j,k) for(int i = j;i <= k;i ++)
#define per(i,j,k) for(int i = j;i >= k;i --)
#define mem(a,p) memset(a,p,sizeof(a))


const ll MOD = 1E9 + 7;
ll qmod(ll a,ll b,ll c) {ll res=1;a%=c; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%c;a=a*a%c;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}

template<typename T, typename S>
void upmax(T& a,S b){if(a<b) a=b;}
template<typename T, typename S>
void upmin(T& a,S b){if(a>b) a=b;}
template<typename T>
void W(T b){cout << b << endl;}
void gettle() {while(1);}
void getre() {int t=0;t/=t;}


/
/
/
/
struct Matrix
{
    ll a[4][4];
    void clear() {
        mem(a,0);
    }
    void gao() {
        rep(i,1,3) rep(j,1,3) a[i][j] = 1;
        a[1][3] = a[3][1] = 0;
    }
    void init() {
        clear();
        a[1][1]=a[2][2]=a[3][3]=1;
    }
    Matrix operator * (const Matrix & x) const {
        Matrix res;  res.clear();
        rep(i,1,3) rep(j,1,3) rep(k,1,3) res.a[i][j] = (res.a[i][j]+a[i][k]*x.a[k][j]%MOD)%MOD;
        return res;
    }
    Matrix mpow(Matrix x, ll k) {
        Matrix res; res.init();
        while(k) {
            if(k&1) res=res*x;
            x=x*x;  k>>=1;
        }
        return res;
    }
};
const int N = 2E5 + 7;
ll bad[4][N];
ll V[N];
int main()
{
    ll n, m;
    cin >> n >> m;
    vector<tuple<int,ll,ll> > till;
    int tot(0);
    rep (i,1,n) {
        int opt;
        ll l,r;
        cin >> opt >> l >> r;
        V[++tot] = l - 1;
        V[++tot] = r;
        till.pb({opt,l,r});
    }
    V[++tot] = 1;
    V[++tot] = m;
    sort(V+1, V+1+tot);
    int nn = unique(V+1,V+1+tot) - (V+1); //不重复数的个数,注意下标

    rep (i,1,n) {
        int opt;
        ll l, r;
        tie(opt,l,r) = till[i-1];
        ll _l = lower_bound(V+1,V+1+nn, l) - V;
        ll _r = lower_bound(V+1,V+1+nn, r) - V;
        bad[opt][_l] ++;
        bad[opt][_r+1] --;
    }
    Matrix ans;  ans.clear();   ans.a[2][1] = 1LL;

    ll now[4];
    mem(now,0);
    rep (i,2,nn) {
        ll len = V[i] - V[i-1];
        Matrix tmp; tmp.gao();
        rep (j,1,3) {
            now[j] += bad[j][i];
            if(now[j]) tmp.a[j][1] = tmp.a[j][2] = tmp.a[j][3] = 0;
        }
        tmp = tmp.mpow(tmp, len);
        ans = tmp * ans;
    }
    cout << ans.a[2][1] << endl;
    return 0;
}





我王企鹅无群

题解:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
区间DP是一种动态规划的方法,用于解决区间范围内的问题。在Codeforces竞赛中,区间DP经常被用于解决一些复杂的字符串或序列相关的问题。 在区间DP中,dp[i][j]表示第一个序列前i个元素和第二个序列前j个元素的最优解。具体的转移方程会根据具体的问题而变化,但是通常会涉及到比较两个序列的元素是否相等,然后根据不同的情况进行状态转移。 对于区间长度为1的情况,可以先进行初始化,然后再通过枚举区间长度和区间左端点,计算出dp[i][j]的值。 以下是一个示例代码,展示了如何使用区间DP来解决一个字符串匹配的问题: #include <cstdio> #include <cstring> #include <string> #include <iostream> #include <algorithm> using namespace std; const int maxn=510; const int inf=0x3f3f3f3f; int n,dp[maxn][maxn]; char s[maxn]; int main() { scanf("%d", &n); scanf("%s", s + 1); for(int i = 1; i <= n; i++) dp[i][i] = 1; for(int i = 1; i <= n; i++) { if(s[i] == s[i - 1]) dp[i][i - 1] = 1; else dp[i][i - 1] = 2; } for(int len = 3; len <= n; len++) { int r; for(int l = 1; l + len - 1 <= n; l++) { r = l + len - 1; dp[l][r] = inf; if(s[l] == s[r]) dp[l][r] = min(dp[l + 1][r], dp[l][r - 1]); else { for(int k = l; k <= r; k++) { dp[l][r] = min(dp[l][r], dp[l][k] + dp[k + 1][r]); } } } } printf("%d\n", dp[n]); return 0; } 希望这个例子能帮助你理解区间DP的基本思想和应用方法。如果你还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值