日常训练2025-1-12

日常训练2025-1-12

P2679 [NOIP2015 提高组] 子串

普及+/提高

https://www.luogu.com.cn/problem/P2679

思路

https://www.luogu.com.cn/article/k0zkdin9

评述

做DP时可以把能想到的有用的状态都定义出来,后序在把不需要的,或者可以根据其他状态推出来的状态删除,逐渐优化。

代码

#include <bits/stdc++.h>
typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 1000000007
using i64 = long long;
const int N = 1e5+5;
void solve(){
int n, m, k;
std::cin >> n >> m >> k;
std::string a, b;
std::cin >> a >> b;
a = ' ' + a;
b = ' ' + b;
std::vector dp(m+1, std::vector<std::vector<int>>(k+1, std::vector<int>(2)));
std::vector ndp(m+1, std::vector<std::vector<int>>(k+1, std::vector<int>(2)));
dp[0][0][0] = 1;
ndp[0][0][0] = 1;
for (int i = 1; i <= n; i++){
ndp = dp;
for (int j = 1; j <= m; j++){
for (int p = 1; p <= k; p++){
if (a[i] == b[j]){
dp[j][p][1] = (ndp[j-1][p][1] + ndp[j-1][p-1][1]) % MOD + ndp[j-1][p-1][0] % MOD;
dp[j][p][1] %= MOD;
dp[j][p][0] = (ndp[j][p][1] + ndp[j][p][0]) % MOD;
}else{
dp[j][p][1] = 0;
dp[j][p][0] = (ndp[j][p][1] + ndp[j][p][0]) % MOD;
}
}
}
}
std::cout << (dp[m][k][0] + dp[m][k][1]) % MOD << '\n';
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
int t = 1, i;
for (i = 0; i < t; i++){
solve();
}
return 0;
}

E - Takahashi is Slime 2

rating:绿色

https://atcoder.jp/contests/abc384/tasks/abc384_e

思路

题目的几个关键点

  1. 每次肯定是找相邻的权值最小的点扩展,如果最小的点都已经无法扩展了,那么就没有点可以扩展了。这个过程有点想Dijstra算法,所以想到要使用优先级队列
  2. 判断大小只需要用已经有的 ans / x 向上取整就行,必须严格比这个值小。

代码

#include <bits/stdc++.h>
typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;
void solve(){
int n, m, x;
std::cin >> n >> m >> x;
int sx, sy;
std::cin >> sx >> sy;
std::vector d(n+1, std::vector<i64>(m+1));
int dir[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
std::vector vis(n+1, std::vector<int>(m+1, 0));
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
std::cin >> d[i][j];
}
}
i64 ans = d[sx][sy];
vis[sx][sy] = 1;
std::priority_queue<std::pair<i64, std::array<int, 2>>, std::vector<std::pair<i64, std::array<int, 2>>>, std::greater<>> q;
for (int i = 0; i < 4; i++){
int dx = sx + dir[i][0];
int dy = sy + dir[i][1];
if (dx <= 0 || dx > n || dy <= 0 || dy > m || vis[dx][dy] == 1) continue;
q.push({d[dx][dy], {dx, dy}});
vis[dx][dy] = 1;
}
while (!q.empty()){
auto [w, arr] = q.top();
q.pop();
// std::cout << w << ' ' << arr[0] << ' ' << arr[1] << '\n';
if (w < ((ans+x-1)/x)){
ans += w;
for (int i = 0; i < 4; i++){
int dx = arr[0] + dir[i][0];
int dy = arr[1] + dir[i][1];
if (dx <= 0 || dx > n || dy <= 0 || dy > m || vis[dx][dy] == 1) continue;
q.push({d[dx][dy], {dx, dy}});
vis[dx][dy] = 1;
}
}else{
break;
}
}
std::cout << ans << '\n';
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
int t = 1, i;
for (i = 0; i < t; i++){
solve();
}
return 0;
}

P1855 榨取kkksc03

rating:普及

https://www.luogu.com.cn/problem/P1855

思路(经典的01背包问题)

/*
记住核心:每个物品只能选一个时从大体积枚举到小体积,每个物品可以选无数次时从小体积枚举到大体积。
f[i][j][k]:表示前i个愿望中,有j块钱和k的时间的情况下能实现的愿望数量的最大值。
初始化:全0
每个愿望有不实现和实现两种情况
状态转移:f[i][j][k] = max(f[i-1][j][k], f[i-1][j-m[i]][k-t[i]] + 1);
由于第一维只有i和i-1所以可以优化掉
*/

代码

#include <bits/stdc++.h>
typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;
/*
f[i][j][k]:表示前i个愿望中,有j块钱和k的时间的情况下能实现的愿望数量的最大值。
初始化:全0
每个愿望有不实现和实现两种情况
状态转移:f[i][j][k] = max(f[i-1][j][k], f[i-1][j-m[i]][k-t[i]] + 1);
由于第一维只有i和i-1所以可以优化掉
*/
void solve(){
int n, M, T;
std::cin >> n >> M >> T;
std::vector<int> m(n+1), t(n+1);
for (int i = 1; i <= n; i++){
std::cin >> m[i] >> t[i];
}
std::vector f(M+1, std::vector<int>(T+1));
for (int i = 1; i <= n; i++){
for (int j = M; j >= m[i]; j--){
for (int k = T; k >= t[i]; k--){
f[j][k] = std::max(f[j][k], f[j-m[i]][k-t[i]] + 1);
}
}
}
std::cout << f[M][T] << '\n';
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
int t = 1, i;
for (i = 0; i < t; i++){
solve();
}
return 0;
}

P1775 石子合并(弱化版)

https://www.luogu.com.cn/problem/P1775

思路(区间DP)

/*
状态定义:f[i][j]表示i...j这个区间合并能得到的最小代价
初始化:f[i][i] = 0,当区间内只有自己时代价为0
状态转移:f[i][j] = min(f[i][j], f[i][k] + f[k+1][j] + sum[j] - sum[i-1]);通过枚举k这个分界线来计算。
*/

代码

#include <bits/stdc++.h>
typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;
void solve(){
int n;
std::cin >> n;
std::vector<int> v(n+1), pre(n+1);
std::vector f(n+1, std::vector<int>(n+1, INF));
for (int i = 1; i <= n ; i++){
std::cin >> v[i];
pre[i] = pre[i-1] + v[i];
f[i][i] = 0;
}
for (int l = 2; l <= n; l++){
for (int i = 1; i <= n - l + 1; i++){
int j = i + l - 1;
for (int k = 1; k < j; k++){
f[i][j] = std::min(f[i][j], f[i][k] + f[k+1][j] + pre[j] - pre[i-1]);
}
}
}
std::cout << f[1][n] << '\n';
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
int t = 1, i;
for (i = 0; i < t; i++){
solve();
}
return 0;
}

C. Trip to the Olympiad

rating:1500

https://codeforces.com/contest/2057/problem/C

思路(按位考虑+Trick)

分析题目的暗示的性质,按位考虑

https://www.bilibili.com/video/BV1mnrRYGEiu/?spm_id_from=333.337.search-card.all.click&vd_source=4a339d299e165d8fe38b9926c5240eae

代码1

#include <bits/stdc++.h>
typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;
void solve(){
int l, r;
std::cin >> l >> r;
int ans = 0;
int k = 30;
while ((r >> k & 1) == (l >> k & 1)){
ans += (r >> k & 1) << k;
k--;
}
ans += 1 << k;
if (ans - 1 == l){
std::cout << l << ' ' << ans << ' ' << ans + 1 << '\n';
}else{
std::cout <<l << ' ' << ans << ' ' << ans - 1<< '\n';
}
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
int t = 1, i;
std::cin >> t;
for (i = 0; i < t; i++){
solve();
}
return 0;
}

代码2

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef basic_string<int> BI;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
mt19937 mrand(random_device{}());
const ll mod=1000000007;
int rnd(int x) { return mrand() % x;}
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
// head
int l,r;
void solve() {
scanf("%d%d",&l,&r);
for (int b=30;b>=0;b--) if ((l>>b)!=(r>>b)) {
int g=(r>>b)<<b;
if (r==g) printf("%d %d %d\n",g,g-1,g-2);
else printf("%d %d %d\n",g+1,g,g-1);
break;
}
}
int _;
int main() {
for (scanf("%d",&_);_;_--) {
solve();
}
}

本文作者:califeee

本文链接:https://www.cnblogs.com/califeee/p/18666791

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   califeee  阅读(2)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.