• UVaLive6435(dp)


    要点

    • 题意:两个数据传输数列,每个数列里有若干个数据包并给出发出时间(t),每个数据包到达的时间(T)(t <= T < t + D),问有多少种到达序列。
    • 将题目转化为第二个数列插入第一个数列。用第一个数列将时间点划分为(N+1)个部分,对于第二数列的每个数据包,预处理它左右范围,即这(N+1)个空,它可以插入哪些空。
    • (i)为第二个数列的第(i)个,(j)为第一个数列的(j-1)(j)的中间空,(dp[i][j])表示把(i)插到(j)空里的方案数,转移即是保证(i-1)(i)的前面某一空即可。
    #include <cstdio>
    #include <vector>
    using std::vector;
    
    typedef long long ll;
    const int maxn = 5e4 + 5;
    const int mod = 1e9 + 9;
    int T, N, M, D;
    int a[maxn], b[maxn];
    ll dp[maxn][205];
    vector<int> v[maxn];
    
    int main() {
    	scanf("%d", &T);
    	for (int kase = 1; kase <= T; kase++) {
    		scanf("%d %d %d", &N, &M, &D);
    		for (int i = 1; i <= N; i++)
    			scanf("%d", &a[i]);
    		for (int i = 1; i <= M; i++)
    			scanf("%d", &b[i]);
    
    		for (int p = 1, i = 1; i <= M; i++) {
    			v[i].clear();
    			for (; p <= N && a[p] + D <= b[i]; p++);
    			for (; p <= N && b[i] + D > a[p]; p++)
    				v[i].push_back(p);
    			v[i].push_back(p), p = v[i][0];//p:1~n+1
    		}
    
    		for (int j = 0; j < v[1].size(); j++)
    			dp[1][j] = 1;
    		for (int i = 2; i <= M; i++) {
    			int p = 0;
    			ll sum = 0LL;
    			for (int j = 0; j < v[i].size(); j++) {
    				for (; p < v[i - 1].size() && v[i - 1][p] <= v[i][j]; p++)
    					sum = (sum + dp[i - 1][p]) % mod;
    				dp[i][j] = sum;
    			}
    		}
    
    		ll ans = 0LL;
    		for (int j = 0; j < v[M].size(); j++)
    			ans = (ans + dp[M][j]) % mod;
    		printf("Case #%d: %lld
    ", kase, ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    sqlserver编程基本语法
    每日一记--技术小细节
    每日一记--jsp
    每日一记--session/servletContext
    每日一记--cookie
    每日一记--HashTable/HashMap/ConcurrentHashMap
    每日一记--Ajax(下)
    每日一记--Axjx
    每日一记--索引/过滤器
    每日一记--酱油日
  • 原文地址:https://www.cnblogs.com/AlphaWA/p/10809172.html
Copyright © 2020-2023  润新知