CF101B Buses dp+数据结构优化

版权声明:版权所有,转载请标明博文出处。 https://blog.csdn.net/HQG_AC/article/details/84677470

题意:
有一个人要从0到n,其间有m趟公交车,这个人可以从 s i > t i 1 s_i->t_i-1 的位置上车,必须在 t i t_i 下车。他想问有多少种方法( %   1 0 9 + 7 \% \ 10^9+7
解法:
很明显要离散,怎么离散就不讲了。车也要按照终点排序
很容易发现这是一道dp题,并且想出dp状态
dp[i]表示乘坐第i趟公交车到达终点的方案数,答案就是所有终点是n的dp值
转移枚举前面那趟公交车进行转移,时间复杂度 O ( m 2 ) O(m^2)
如何优化?
似乎很容易,我们的上一趟公交车肯定是在 s i > t i 1 s_i->t_i-1 范围转移来的,所以我们只要把从 s i > t i 1 s_i->t_i-1 的dp值加到dp[i]就行了,而因为排序,起点在前的一定编号小,于是我们只要在原序列中进行 l o w e r _ b o u n d lower\_bound 就行了,
再通过前缀和求出一段dp值加入到dp[i]里,就OK了
别看总场通常,那是因为头文件的原因,真正main函数里的代码还是挺短的

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <vector>
#include <bitset>
#include <cstdio>
#include <cctype>
#include <string>
#include <cstring>
#include <cassert>
#include <climits>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std ;

#define rep(i, a, b) for (int (i) = (a); (i) <= (b); (i)++)
#define Rep(i, a, b) for (int (i) = (a) - 1; (i) < (b); (i)++)
#define REP(i, a, b) for (int (i) = (a); (i) >= (b); (i)--)
#define clr(a) memset(a, 0, sizeof(a))
#define Sort(a, len, cmp) sort(a + 1, a + len + 1, cmp)
#define ass(a, sum) memset(a, sum, sizeof(a))

#define ls ((rt) << 1)
#define rs ((rt) << 1 | 1)
#define lowbit(x) (x & -x)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define endl '\n'
#define ENDL cout << endl
#define SZ(x) ((int)x.size())

typedef long long ll ;
typedef unsigned long long ull ;
typedef vector <int> vi ;
typedef pair <int, int> pii ;
typedef pair <ll, ll> pll ;
typedef map <int, int> mii ;
typedef map <string, int> msi ;
typedef map <ll, ll> mll ;

const int N = 100010 ;
const double eps = 1e-8 ;
const int iinf = INT_MAX ;
const ll linf = 2e18 ;
const double dinf = 1e30 ;
const int MOD = 1000000007 ;

inline int read(){
    int X = 0, w = 0 ;
	char ch = 0 ;
    while (!isdigit(ch)) { w |= ch == '-' ; ch = getchar() ; }
    while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar() ;
    return w ? - X : X ;
}

void write(int x){
     if (x < 0) putchar('-'), x = - x ;
     if (x > 9) write(x / 10) ;
     putchar(x % 10 + '0') ;
}

void print(int x) {
	cout << x << endl ;
	exit(0) ;
}

void PRINT(string x) {
	cout << x << endl ;
	exit(0) ;
}

void douout(double x){
	 printf("%lf\n", x + 0.0000000001) ;
}

int dp[N], sum[N] ;
int n, m, ans ;

int main() {
	scanf("%d%d", &n, &m) ;
	vector <pii> a(m) ; vi v(m) ;
	for (int i = 0, s, t; i < m; i++) {
		scanf("%d%d", &s, &t) ;
		a[i] = mp(t, s) ;
		v[i] = t ;
	}
	sort(a.begin(), a.end()) ; sort(v.begin(), v.end()) ;
	for (int i = 0; i < m; i++) {
		int f = a[i].se, t = a[i].fi ;
		if (f == 0) dp[i] = 1 ;
		int S = lower_bound(v.begin(), v.end(), f) - v.begin() ;
		int T = lower_bound(v.begin(), v.end(), t) - v.begin() ;
		dp[i] = (dp[i] + sum[T] - sum[S] + MOD) % MOD ;
		sum[i + 1] = (sum[i] + dp[i]) % MOD ;
	}
	for (int i = 0; i < m; i++) if (a[i].fi == n) ans = (ans + dp[i]) % MOD ;
	printf("%d\n", ans) ;
}

/*
写代码时请注意:
	1.是否要开Long Long?数组边界处理好了么?
	2.实数精度有没有处理?
	3.特殊情况处理好了么?
	4.做一些总比不做好。
思考提醒:
	1.最大值和最小值问题可不可以用二分答案?
	2.有没有贪心策略?否则能不能dp?
*/

猜你喜欢

转载自blog.csdn.net/HQG_AC/article/details/84677470