做题笔记(二)
[CSP-S 2023] 消消乐
题目传送门
思路
考虑 DP。
显然,设
那么我们当前位置为
到这里其实都很简单的,去年的我考场上也是想到这里就戛然而止,最后写了一个 50pts
的暴力遗憾离场。
但我们可以考虑一个一个往前找,就是那个
假设当前位置为
由于最多只有
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
string s;
int f[2000005]={0},n,ans=0;
int last[2000005]={0};
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>s; s=" "+s;
for(int i=1;i<=n;i++){
for(int j=i-1;j>0;j=last[j]-1){
if(s[i]==s[j]){
last[i]=j;
break;
}
}
if(last[i]!=0)
f[i]+=(1ll+f[last[i]-1]);
}
for(int i=1;i<=n;i++)
ans+=f[i];
cout<<ans<<endl;
return 0;
}
[12.3 互测 A] 简单
题目传送门
不知道有没有原题咕咕咕。
题目大意
你要炸掉在
定义裸露的方块为它的上方,左方,右方有一个方向没有方块。
定义一次轰炸为消除所有裸露的方块。求出要使所有方块消除所需的轰炸次数。
思路
一道很神奇的思维题。其实难度不大,但是硬控了我 1h。
定义
不难看出,
注意到,每一个位置只能是从旁边消除或者从上面一个一个消除下来。
那么:
反过来也一样。
之间复杂度
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN=1e5+5;
int n,h[MAXN]={0},f[MAXN]={0};
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
cin>>h[i];
for(int i=1;i<=n;i++){
if(i==1) f[i]=1;
else f[i]=min(h[i],f[i-1]+1);
}
for(int i=n;i>=1;i--){
if(i==n) f[i]=1;
else f[i]=min(f[i+1]+1,f[i]);
}
int ans=0;
for(int i=1;i<=n;i++)
ans=max(f[i],ans);
cout<<ans<<endl;
return 0;
}
字串距离
题目传送门
思路
比较能看出来这是一个 DP,难度大概在 CSP-S 的 T1 或者 T2。
很容易想到设
转移方程还是比较板的:
但是这样直接写之后答案会错,转移方程的正确性不言而喻,考虑初始化。
显然有:
然后就可以发现:
加上初始化后就可以轻松 AC
,时间复杂度
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
string a,b;
int k,f[2005][2005]={0};
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>a>>b>>k;
a=" "+a; b=" "+b;
f[0][0]=0;
for(int i=1;i<a.size();i++)
f[i][0]=i*k;
for(int i=1;i<b.size();i++)
f[0][i]=i*k;
for(int i=1;i<a.size();i++){
for(int j=1;j<b.size();j++){
f[i][j]=min(min(f[i-1][j]+k,f[i][j-1]+k),f[i-1][j-1]+abs(a[i]-b[j]));
}
}
cout<<f[a.size()-1][b.size()-1]<<endl;
return 0;
}
教主的花园
题目传送门
思路
这道题很显然是 DP。
先设一个 DP 转移的数组:
发现如果
显然有:
然后加上环形 DP 的简单处理就可以了,时间复杂度
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN=2e5+5;
int n,a[MAXN],b[MAXN],c[MAXN];
int f[MAXN][4][2]={0},ans=0;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i]>>b[i]>>c[i];
for(int k=1;k<=3;k++){
memset(f,0,sizeof(f));
if(k==1) f[1][1][0]=a[1];
else if(k==2) f[1][2][0]=b[1],f[1][2][1]=b[1];
else f[1][3][1]=c[1];
for(int i=2;i<=n;i++){
f[i][1][0]=max(f[i-1][2][1]+a[i],f[i-1][3][1]+a[i]);
f[i][2][0]=f[i-1][3][1]+b[i];
f[i][2][1]=f[i-1][1][0]+b[i];
f[i][3][1]=max(f[i-1][1][0]+c[i],f[i-1][2][0]+c[i]);
}
if(k==1) ans=max(max(f[n][2][1],f[n][3][1]),ans);
else if(k==2) ans=max(max(f[n][3][1],f[n][1][0]),ans);
else ans=max(max(f[n][1][0],f[n][2][0]),ans);
}
cout<<ans<<endl;
return 0;
}
Battling with Numbers
题目传送门
思路
一个很思维的思维题。发现洛谷上的题解证明部分略少,故此处给出较严谨的证明。
- 命题一:
。
证明:因为
- 命题二:不存在一个质数
,使得 并且满足 。
证明:假设
- 命题三:令
为 的不同质因子个数,那么 数对的个数为 。
证明:将
根据命题三,我们只需要分解
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN=1e5+5,MOD=998244353;
const int MAXNUM=2e6+5;
int n,a[MAXN]={0},b[MAXN]={0};
int m,c[MAXN]={0},d[MAXN]={0};
int pa[MAXNUM]={0};
int cnt=0;
int qpow(int a,int b){
int res=1;
while(b){
if(b&1) res=((res%MOD)*(a%MOD))%MOD;
a=((a%MOD)*(a%MOD))%MOD;
b>>=1;
}
return res;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++){
cin>>b[i];
pa[a[i]]=b[i];
}
cin>>m;
for(int i=1;i<=m;i++)
cin>>c[i];
for(int i=1;i<=m;i++)
cin>>d[i];
for(int i=1;i<=m;i++){
if(pa[c[i]]<d[i]){
cout<<0<<endl;
return 0;
}
else pa[c[i]]-=d[i];
}
for(int i=1;i<=n;i++)
if(pa[a[i]]>0) cnt++;
cout<<qpow(2ll,cnt)<<endl;
return 0;
}
[翟翟 OI Round #1 1A] 征兵
题目传送门
思路
一个需要小小思考的绿题,难度可能比 CSP-S 的 T1 稍低。
显然面对这种亲戚关系,使用并查集是可以的。也就是说,在处理完这若干个亲戚关系之后,我们可以得到一堆亲戚集合
复杂度取决于并查集。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN=3000010;
int f[MAXN]={0},ct=0,mx[MAXN]={0},ans=0,a[MAXN];
bool b[MAXN]={0};
int find(int v){
if(f[v]==v) return v;
else return f[v]=find(f[v]);
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n,u,v; cin>>n;
for(int i=1;i<=n;i++)
f[i]=i;
for(int i=1;i<=n;i++)
cin>>a[i];
while(cin>>u>>v){
int x=find(u),y=find(v);
if(x!=y)f[x]=y;
}
for(int i=1;i<=n;i++){
if(!b[find(i)]) ct++;
b[find(i)]=1;
mx[find(i)]=max(a[i],mx[find(i)]);
}
for(int i=1;i<=n;i++)
if(b[i]) ans+=mx[i];
cout<<ct<<endl<<ans<<endl;
return 0;
}
[翟翟 OI Round #1 1B] 军训
题目传送门
思路
感觉一个很板的 DP。
首先为了简便,抽象题面:有一个序列
设
显然可以分类讨论:
-
如果
: 。 -
如果
: 。
然后直接写即可,时间复杂度
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n,m; cin>>n>>m;
int f[60][10]={0}; f[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<m;j++)
f[i][0]+=f[i-1][j];
for(int j=1;j<m;j++)
f[i][j]+=f[i-1][j-1];
}
int ans=0;
for(int j=0;j<m;j++)
ans+=f[n][j];
cout<<ans<<endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现