日常刷题2025-3-1

日常刷题2025-3-1

完美串

111 / 486

https://ac.nowcoder.com/acm/contest/101964/B

思路:构造

此题是一道让相同的字符相隔尽量远的构造,构造时每次选择剩余最多且在 kk 长度以内不冲突的字符构建即可。

构造思路非常值得学习

评述

想到了题目做法但是不会写代码

代码

#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(){
std::string s;
std::cin >> s;
int n = s.size();
std::vector<pii> p(30);
std::vector<int> ans;
std::vector<int> a(26);
for (auto e : s) a[e-'a']++;
auto check = [&](int mid)->bool{
ans.clear();
std::priority_queue<pii> q;
for (int i = 0; i < 26; i++) if (a[i]) q.push({a[i], i});
while (1){
if (q.size() < mid){
while (q.size()){
pii t = q.top();
q.pop();
ans.push_back(t.second);
if (t.first > 1) return 0;
}
return 1;
}
for (int i = 1; i <= mid; i++){
pii t = q.top();
q.pop();
ans.push_back(t.second);
p[i] = t;
}
for (int i = 1; i <= mid; i++){
if (p[i].first > 1) q.push({p[i].first-1, p[i].second});
}
}
};
int l = 1, r = std::min(n ,26);
while (l < r){
int mid = (l + r + 1)>>1;
if (check(mid)) l = mid;
else r = mid - 1;
}
check(l);
std::cout << l << '\n';
for (int i = 0; i < ans.size(); i++){
std::cout << char(ans[i]+'a') ;
}
std::cout << '\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;
}

P1004 [NOIP 2000 提高组] 方格取数

绿色

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

思路:四维DP

首先观察到此题的数据范围非常(!)小,所以优先考虑爆搜,爆搜有两种,一种是dfs和bfs,还有一种就是DP。我们选择DP的解法,同时处理两次行程能得到的总的最大值

f[i][j][k][l]:表示第一次走到 i 和 j ,第二次走到 k 和 l 能得到的最大值。

评述

可惜思考的时候没有想到DP,比较傻×了。

代码

#include<cstdio>
#include<iostream>
using namespace std;
const int N=11;
int dp[N][N][N][N];
int a[N][N];
int n,x,y,z;
int main()
{
scanf("%d",&n);
for(;;)
{
scanf("%d%d%d",&x,&y,&z);
if(x==y&&y==z&&z==0)
{
break;
}
else
{
a[x][y]=z;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
for(int k=1;k<=n;k++)
{
for(int l=1;l<=n;l++)
{
dp[i][j][k][l]=max(max(dp[i-1][j][k-1][l],dp[i-1][j][k][l-1]),max(dp[i][j-1][k-1][l],dp[i][j-1][k][l-1]))+a[i][j]+a[k][l];
if(i==k&&l==j)dp[i][j][k][l]-=a[i][j];//注意判断这个点走过几次并处理
}
}
}
}
printf("%d",dp[n][n][n][n]);
return 0;
}

P1005 [NOIP 2007 提高组] 矩阵取数游戏

绿色

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

思路:区间DP

  • n行最大得分和,每一行取数又不会影响到其他行,那么只要确保每一行得分最大,管好自家孩子就行了。(这个在动规中叫最优子结构
  • 每次取数是在边缘取,那么每次取数完剩下来的元素一定是在一个完整的一个区间中,又是求最优解,区间DP应运而生。

评述

想了一下DP结果马上被自己否决了,理由是线性DP都是沿着一个方向,这题一会取左边一会取右边肯定不能用线性DP。但是这不恰好是区间DP的主场吗?人傻了

代码

#include <bits/stdc++.h>
using namespace std;
const int MAXN=81;
inline void input(__int128 &s)
{
s=0;
char c=' ';
while(c>'9'||c<'0') c=getchar();
while(c>='0'&&c<='9')
{
s=s*10+c-'0';
c=getchar();
}
}
inline void output(__int128 x)
{
if(x>9)
output(x/10);
putchar(x%10+'0');
}
int n, m;
__int128 game[MAXN][MAXN];
__int128 f[MAXN][MAXN];
__int128 solve(__int128 a[])
{
memset(f,0,sizeof(f));
for(int len=0;len<=m;++len)
for(int i=1;i+len<=m;++i)
f[i][i+len]=max(2*f[i+1][i+len]+2*a[i],2*f[i][i+len-1]+2*a[i+len]);
return f[1][m];
}
__int128 ans=0;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
input(game[i][j]);
for(int i=1;i<=n;i++)
ans+=solve(game[i]);
output(ans);
return 0;
}

本文作者:califeee

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

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

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