https://ac.nowcoder.com/acm/contest/3006/F
题目描述
在ACM比赛里,除了CE以外都是有效的提交。每一个提交都会有其评测的结果,或是AC,或是RJ(Rejected,包含各种不通过的情况)。往往一个人上去提交的时候,总有一个队友会坐在边上等着结果。那个人,往往都是只读题不写题的云选手~
牛牛战队里也有这样的云选手——牛能。当牛能看到有效提交得到了AC以后,都会大呼一声“你好能啊!”,反之,如果得到了RJ的话,就会化身为喷子,说xxx句“你能不能行啊!”。大家比赛的都十分紧张,这样的大声呼喊未免会引起旁边队伍的注意。
当然牛牛战队交题的时候也很小心,一旦这一发出现了RJ,下一发有效提交一定能获得AC。
比赛结束了以后,旁边的一支队伍愤怒的跑过来说:你们比赛的时候吵不吵啊,一直在这大吼,吼了这么多句!
激烈的争吵引起了吃瓜群众的注意,吃瓜群众问道:吼了多少句啊,这么讨厌的吗
“啊……我也记不清了,大概是在这个区间吧”
作为吃瓜群众的你,想根据这个信息算出,这个队伍有多少种有效提交结果序列的可能呢?
思路
很简单一个dp而已,可惜我没看到上面红色标记那句话,疯狂WA
表示前面说了句话,并且最后一次AC了,就是前面说了句话并且最后一发RJ了
考虑状态转移吧
- 容易一点,就是前面句话最后一个不论结果,所以是
- 也不复杂,就是需要用上面红色的那句话,如果前面那个状态的最后结果是RJ,当前这个RJ就不会是它的下一个状态,因此只有
这就求出来说了每句话的方案数了,然后求一个前缀和,查询区间时,就是结果,减法注意是负数,加个mod再取模即可
/*************************************************************************
> File Name: F.cpp
> Author: amoscykl
> Mail: amoscykl@163.com
> Created Time: 2020年02月14日 星期五 18时24分54秒
************************************************************************/
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int q, n, x;
#define mem(a, b) memset(a, b, sizeof a)
typedef long long ll;
ll f[N][4];
const int mod = 1e9 + 7;
int main()
{
ios::sync_with_stdio(0);
cin >> x;
mem(f, 0);
// f[i][0] 说了i句话,并且最后一次ac
// f[i][1] 说了i句话,并且最后一次rj
// 注意:rj之后必定ac
f[0][0] = 1;
f[0][1] = 0;
f[0][2] = 1;
for (int i = 1; i <= 100000; i++){
f[i][0] = (f[i - 1][0] + f[i - 1][1]) % mod;
if (i >= x){
f[i][1] = f[i - x][0];
f[i][1] %= mod;
}
}
for (int i = 1; i <= 100000; i++){
f[i][2] = (f[i - 1][2] + f[i][1] + f[i][0]) % mod;
}
cin >> q;
while (q--){
int l, r;
cin >> l >> r;
ll res = f[r][2] - f[l - 1][2];
res = (res + mod) % mod;
cout << res << "\n";
}
return 0;
}