AtCoder - abc179_d 前缀和优化dp

题意:
给正整数 n n n ( n < = 1 e 5 ) (n<=1e5) (n<=1e5) k k k k k k代表 k k k ( k < = 10 ) (k<=10) (k<=10)个区间,求 1 1 1 n n n 有多少种方案。
思路:
我们可以发现,第 i i i个点的答案为前 i i i 1 − i 1-i 1i区间答案的累加,而现在我们只知道有 k k k个区间可以利用,同理我们类别 1 − i 1-i 1i的方式取,可用区间的元素来构造答案即可。

参考代码

/*
 * @Descripttion: fst
 * @version:
 * @Author: Vain
 * @Date: 2020-08-26 11:58:46
 * @LastEditors: sueRimn
 * @LastEditTime: 2020-11-02 20:54:09
 */
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
vector<int> f[maxn];
int a[maxn];
int vis[maxn * 5];
void read(ll &v)
{
    
    
	ll k = 1;
	v = 0;
	ll c = getchar();
	while (c < '0' || c > '9')
	{
    
    
		if (c == '-')
			k = 0;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
		v = (v << 3) + (v << 1) + (c - 48), c = getchar();
	if (k == 0)
		v = -v;
}
ll dp[maxn], sum[maxn];
pair<int, int> seg[15];
int main()
{
    
    
	ll n, k;
	read(n), read(k);
	for (int i = 1; i <= k; i++)
	{
    
    
		scanf("%d %d", &seg[i].first, &seg[i].second);
	}
	dp[1] = sum[1] = 1;
	for (int i = 2; i <= n; i++)
	{
    
    
		for (int j = 1; j <= k; j++)
		{
    
    
			int l = seg[j].first, r = seg[j].second;
			dp[i] = (dp[i] + sum[max(0, i - l)] - sum[max(0, i - r - 1)] + 998244353) % 998244353;
		}
		sum[i] = (sum[i - 1] + dp[i]) % 998244353;
	}
	cout << dp[n] << endl;
}
 

猜你喜欢

转载自blog.csdn.net/yangzijiangac/article/details/109457508
今日推荐