目录
3.Acwing1090绿色通道(单调队列优化dp + 二分答案)
1.Atcoder261D
(1)题目描述
(2)题目分析:给定你两个序列,第一个序列是第i场硬币朝上你能获得的奖励,第二个序列是你连续i场向上你能获得的奖励,现在问你丢n次硬币,能获得的最大奖励是多少。
(3)解题思路:我们可以考虑dp,
dp[i][j] 表示从我当前是第i场,前j场连胜。
那么我们很容易退出状态转移方程
处理边界情况
1.j < i : dp[i][0] = max(dp[i][0],dp[i - 1][j]);
2.j != 0: dp[i][j] = max(dp[i][j],dp[i - 1][j - 1] + w1[i] + w2[j]);
(4)代码实现:
const int N = 5010;
long long dp[N][N],w1[N],w2[N];
int main()
{
int n,m;
cin >> n >> m;
for(int i = 1;i <= n;i++) cin >> w1[i];
for(int i = 1;i <= m;i++) {
int u,v;
cin >> u >> v;
w2[u] = v;
}
for(int i = 1;i <= n;i++) {
for(int j = 0;j <= i;j++) {
if(j < i) dp[i][0] = max(dp[i][0],dp[i - 1][j]);
if(j != 0) dp[i][j] = max(dp[i][j],dp[i - 1][j - 1] + w1[i] + w2[j]);
}
}
long long res = 0;
for(int i = 0;i <= n;i++) res = max(dp[n][i],res);
cout << res << endl;
return 0;
}
2.牛客多校竞赛第1场I题(概率DP)
(1) 题目描述
当时没怎么学过概率Dp,这个题也就很顺利的没有当场写出来,后面知道是板子题。。。。
(2)题意分析:给你一副麻将,问你这把牌凑成七对的次数是多少。
(3)解题思路:dp[i][j]表示牌库还有i张牌,当前手上还有j张单牌的方案数
下一张牌可以凑对:dp[i][j] = 3 * j / i * (dp[i - 1][j - 2] + 1)
下一张牌不可凑对:dp[i][j] = (i - 3 * j) / i * dp[i - 1][j] + 1)
因此dp[i][j] = 3 * j / i * (dp[i - 1][j - 2] + 1) + dp[i][j] = (i - 3 * j) / i * dp[i - 1][j] + 1)
处理边界情况j == 0 直接return 0
处理边界情况j == 1 dp[i][j] = (i - 3 * j * (dp[i - 1][j] + 1)) + 3 * j / i * 1)
(4)代码实现:
#include "bits/stdc++.h"
using namespace std;
map<string,int> mp;
long long dp[150][20];
const int mod = 1e9 + 7;
long long qpow(long long a,int p)
{
long long res = 1;
while(p) {
if(p & 1) res = res * a % mod;
a = a * a % mod;
p >>= 1;
}
return res;
}
long long dfs(int i,int j)
{
if(dp[i][j] != -1) return dp[i][j];
if(j == 0) return 0;
long long p1 = (i - 3 * j) * qpow(i,mod - 2) % mod;
long long p2 = (3 * j) * qpow(i,mod - 2) % mod;
if(j == 1) dp[i][j] = (p1 * (dfs(i - 1,j) + 1) % mod + p2 * 1 % mod) % mod;
else dp[i][j] = ((p1 * (dfs(i - 1,j) + 1) % mod + p2 * (dfs(i - 1,j - 2) + 1) % mod)) % mod;
return dp[i][j];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
memset(dp,-1,sizeof(dp));
int T,cas = 1;
cin >> T;
for(;cas <= T;cas++) {
int n = 0;
string s;
cin >> s;
mp.clear();
for(int i = 0;i < 13;i++) {
string p = "";
p += s[2 * i];
p += s[2 * i + 1];
mp[p]++;
}
for(auto x:mp) n += (x.second == 1);
cout << "Case #" << cas << ": " << dfs(123,n) << endl;
}
return 0;
}
3.Acwing1090绿色通道(单调队列优化dp + 二分答案)
(1)题目描述
(2)题意分析:给定你一个序列,问你现在能用不超过t分钟,并且空题段最长。
(3)解题思路:我们直接二分空题段的长度,每次都进行一次check操作,check操作使用单调队列优化dp,看能否达到t分钟内并且空段是mid的情况下成立。
(4)代码实现:
#include "bits/stdc++.h"
using namespace std;
const int N = 50010;
int f[N],q[N],w[N];
int n,m;
bool check(int k)
{
int hh,tt;
hh = tt = 0;
f[0] = 0;
for(int i = 1;i <= n;i++) {
//因为第i-k-1段能用到,因此需要判一下
if(hh <= tt && q[hh] < i - k - 1) hh++;
f[i] = w[i] + f[q[hh]];
while(hh <= tt && f[i] <= f[q[tt]]) tt--;
q[++tt] = i;
}
for(int i = n - k;i <= n;i++) if(f[i] <= m) return true;
return false;
}
int main()
{
cin >> n >> m;
for(int i = 1;i <= n;i++) cin >> w[i];
int l = 0,r = n;
while(l <= r) {
int mid = (l + r) >> 1;
if(check(mid)) r = mid - 1;
else l = mid + 1;
}
cout << l << endl;
return 0;
}
4.Atcoder265E
(1)题目描述
(2)题意分析
这个题给定我们三个操作,从0,0开始,不能走到非法点上的最后不同的路径的条数。
(3)解题思路
对于这三个操作,我们分析题目条件,最多不超过300次,因此我们可以枚举两个操作,然后算出另一个操作的次数。仅需进行转移即可。
(4)代码实现
#include "bits/stdc++.h"
#define PII pair<int,int>
using namespace std;
const int N = 3e2 + 10,mod = 998244353;
map <PII,bool> mp;
int dp[N][N][N];
int ans = 0;
void solve()
{
int n,m;
int a,b,c,d,e,f;
cin >> n >> m;
cin >> a >> b >> c >> d >> e >> f;
for(int i = 1;i <= m;i++) {
int x,y;
cin >> x >> y;
mp[{x,y}] = true;
}
dp[0][0][0] = 1;
for(int i = 1;i <= n;i++) {
for(int j = 0;j <= i;j++) {
for(int k = 0;k <= i;k++) {
if(k + j > i) break;
//枚举第三个操作的数量
int q = i - j - k;
int x = j * a + k * c + q * e;
int y = j * b + k * d + q * f;
if(mp.count({x,y})) continue;
if(!mp.count({x - a,y - b}) && j) dp[j][k][q] = (dp[j][k][q] + dp[j - 1][k][q]) % mod;
if(!mp.count({x - c,y - d}) && k) dp[j][k][q] = (dp[j][k][q] + dp[j][k - 1][q]) % mod;
if(!mp.count({x - e,y - f}) && q) dp[j][k][q] = (dp[j][k][q] + dp[j][k][q - 1]) % mod;
if(i == n) ans = (ans + dp[j][k][q]) % mod;
}
}
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int T;
T = 1;
while(T --) {
solve();
}
return 0;
}