题目链接:http://codeforces.com/contest/712/problem/D
A初始有一个分数a,B初始有一个分数b,有t轮比赛,每次比赛都可以取[-k, k]之间的数,问你最后A比B大的情况有多少种。
dpA[i][j]表示第i轮获得j分的情况数。因为第i轮只和第i-1轮有关,所以这里i用滚动数组优化。
要是普通做法3个for就会超时,所以要用前缀和优化,dpA[i][j]可以由一段连续的dp[i - 1][x]转移过来,所以用sumA数组存取dp[i - 1][x]的前缀和。就可以省去一个for。
B同理。
1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm> 3 #include <iostream> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cstdio> 7 #include <vector> 8 #include <cmath> 9 #include <ctime> 10 #include <list> 11 #include <set> 12 #include <map> 13 using namespace std; 14 typedef long long LL; 15 typedef pair <int, int> P; 16 const int N = 2e5 + 205; 17 LL dp[2][N], mod = 1e9 + 7, sum[N], dpA[2][N], sumA[N]; 18 19 int main() 20 { 21 int a, b, k, t; 22 scanf("%d %d %d %d", &a, &b, &k, &t); 23 a += 1e5, b += 1e5; 24 dp[0][b] = 1; 25 dpA[0][a] = 1; 26 sum[b] = 1, sumA[a] = 1; 27 for(int i = 1; i <= t; ++i) { 28 for(int j = 1; j < N; ++j) { 29 dp[i%2][j] = dpA[i%2][j] = 0; 30 } 31 for(int j = -k*i; j <= k*i; ++j) { 32 int l = max(-k*(i - 1), j - k), r = min(k*(i - 1), j + k); 33 dp[i % 2][b + j] = ((sum[r + b] - sum[l - 1 + b] + dp[i % 2][b + j]) % mod + mod) % mod; 34 dpA[i % 2][a + j] = ((sumA[r + a] - sumA[l - 1 + a] + dpA[i % 2][a + j]) % mod + mod) % mod; 35 } 36 for(int j = 1; j < N; ++j) { //在每轮中sum都会重新更新 37 sum[j] = (sum[j - 1] + dp[i % 2][j]) % mod; 38 sumA[j] = (sumA[j - 1] + dpA[i % 2][j]) % mod; 39 } 40 } 41 LL ans = 0; 42 for(int i = 1; i < N; ++i) { 43 ans = (ans + sum[i - 1]*dpA[t % 2][i] % mod) % mod; 44 } 45 printf("%lld ", ans); 46 return 0; 47 }