题目
https://vjudge.net/problem/Gym-101490K
题意
给出圆形赛车跑道长度 L(十米单位),然后要在跑道上建立设施,每两个相邻设施之间不能超过 S 个十米单位,问总方案数。
题解
问总方案数以及要模 123456789,可知数据十分巨大,很快可以想到这是一道 DP 题。我们定义 dp【i】为跑道不是圆形且长度为 i 并在 i 位置建立设施时的方案数。sum【i】为 dp【i】的前缀和。
由于相邻距离不能超过 S,所以第一个设施放哪决定了最后面哪几个 dp 数组的值是能够被记录进答案的,而以不同的位置作为起始位置又保证了没有重复计算答案。所以这时候我们考虑不同初始化的情况。
初始化 dp【1】 = 1 时,累加答案 sum【L】 - sum【L - S】。
初始化 dp【2】= 1 时,累加答案 sum【L】 - sum【L - S + 1】。
……
初始化 dp【S】= 1 时,累加答案 sum【L】- sum【L - 1】。
这样我们就可以……怎么可能就这么结束了呢
当S够大时,反复重新初始化会使得题目的时间复杂度上升到 O(n^2) 的程度。
仔细观察可以发现,初始化 dp【2】 = 1 时,sum【L】- sum【L - S - 1】 是不是就相当于初始化 dp【1】= 1 时,sum【L - 1】- sum【L - S】。那么上述式子就转化成了
初始化 dp【1】= 1 时,答案就是 ( sum【L】- sum【L - S】) + ( sum【L - 1】- sum【L - S】) +……+ ( sum【L - S + 1】- sum【L - S】)。
1 #include <bits/stdc++.h> 2 #define ll long long 3 #define ull unsigned long long 4 #define met(a, b) memset(a, b, sizeof(a)) 5 #define rep(i, a, b) for(int i = a; i <= b; i++) 6 #define bep(i, a, b) for(int i = a; i >= b; i--) 7 #define lowbit(x) (x&(-x)) 8 #define MID (l + r) / 2 9 #define ls pos*2 10 #define rs pos*2+1 11 #define pb push_back 12 #define ios() ios::sync_with_stdio(0) 13 14 using namespace std; 15 16 const int maxn = 1e6 + 1010; 17 const int inf = 0x3f3f3f3f; 18 const ll INF = 0x3f3f3f3f3f3f3f3f; 19 const ll mod = 123456789; 20 21 ll dp[maxn]; 22 ll sum[maxn]; 23 24 int main() { 25 ll n, m; 26 cin >> n >> m; 27 dp[1] = 1; 28 sum[1] = 1; 29 rep(i, 2, n) { 30 dp[i] = sum[i-1] - sum[max(0ll, i-m-1)]; 31 sum[i] = sum[i-1] + dp[i]; 32 dp[i] %= mod; 33 sum[i] %= mod; 34 } 35 ll res = 0; 36 bep(i, n, n-m) { 37 res += sum[i] - sum[n-m]; 38 res %= mod; 39 } 40 if(res < 0) res += mod; 41 cout << res << endl; 42 43 return 0; 44 }