刷题笔记(2023.9.22)
路灯2
一眼区间
然后可以推出状态转移方程为
int A=f[i+1][j][0]+(p[i+1]-p[i])*(sum[n]-sum[j]+sum[i]);
int B=f[i+1][j][1]+(p[j]-p[i])*(sum[n]-sum[j]+sum[i]);
int C=f[i][j-1][0]+(p[j]-p[i])*(sum[n]-sum[j-1]+sum[i-1]);
int D=f[i][j-1][1]+(p[j]-p[j-1])*(sum[n]-sum[j-1]+sum[i-1]);
f[i][j][0]=min(A,B);
f[i][j][1]=min(C,D);
其中
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=55;
int n,c,x;
int p[N],sum[N],f[N][N][2];
inline int read(){
char c=getchar();int f=1,x=0;
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int main(){
n=read();
c=read();
for(int i=1;i<=n;i++){
p[i]=read();
x=read();
sum[i]=sum[i-1]+x;
}
memset(f,INF,sizeof(f));
f[c][c][0]=f[c][c][1]=0;
for(int l=2;l<=n;l++){
for(int i=1;i+l-1<=n;i++){
int j=i+l-1;
int A=f[i+1][j][0]+(p[i+1]-p[i])*(sum[n]-sum[j]+sum[i]);
int B=f[i+1][j][1]+(p[j]-p[i])*(sum[n]-sum[j]+sum[i]);
int C=f[i][j-1][0]+(p[j]-p[i])*(sum[n]-sum[j-1]+sum[i-1]);
int D=f[i][j-1][1]+(p[j]-p[j-1])*(sum[n]-sum[j-1]+sum[i-1]);
f[i][j][0]=min(A,B);
f[i][j][1]=min(C,D);
}
}
printf("%d",min(f[1][n][0],f[1][n][1]));
return 0;
}
搭建双塔
设
那么
其中第一个为不选,第二个为选的第一座塔,第三个为选的第三座塔。
最后再查找
在实际操作中,第一维因为是顺序动规,所以可以直接删去,降成两维。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=110;
const int M=1e4+100;
int n,sum,ans;
int h[N];
bool f[M][M];
inline int read(){
char c=getchar();int f=1,x=0;
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int main(){
n=read();
for(int i=1;i<=n;i++) h[i]=read(),sum+=h[i];
sum/=2;
f[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=sum;j>=0;j--){
for(int k=sum;k>=0;k--){
bool f1=f[j][k],f2=0,f3=0;
if(j>=h[i]) f2=f[j-h[i]][k];
if(k>=h[i]) f3=f[j][k-h[i]];
f[j][k]=f1||f2||f3;
}
}
}
for(int i=1;i<=sum;i++) if(f[i][i]) ans=i;
if(ans) printf("%d",ans);
else printf("Impossible");
return 0;
}
暗黑破坏神
很明显的动态规划,
状态转移方程就是
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=110;
struct node{
int c,p;
int w[N*5];
}a[N];
int n,m;
int f[N][N*5];
inline int read(){
char c=getchar();int f=1,x=0;
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int main(){
n=read();
m=read();
for(int i=1;i<=n;i++){
a[i].c=read();
a[i].p=read();
for(int j=1;j<=a[i].p;j++) a[i].w[j]=read();
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
f[i][j]=f[i-1][j];
for(int k=0;k<=a[i].p;k++){
if(k*a[i].c>j) break;
f[i][j]=max(f[i][j],f[i-1][j-k*a[i].c]+a[i].w[k]);
}
}
}
printf("%d",f[n][m]);
return 0;
}
沙盘游戏
就是一道模板的最小子矩阵和,不用多说了...
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=310;
int n,m,ans;
int a[N][N],b[N][N],f[N];
inline int read(){
char c=getchar();int f=1,x=0;
while (c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while (c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int main(){
n=read();
m=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]=read();
}
}
for(int i=1;i<=n;i++){
memset(b,0,sizeof(b));
for(int j=i;j<=n;j++){
for(int k=1;k<=m;k++){
b[j][k]=a[j][k]+b[j-1][k];
}
memset(f,0,sizeof(f));
for(int k=1;k<=m;k++){
f[k]=max(b[j][k],f[k-1]+b[j][k]);
ans=max(ans,f[k]);
}
}
}
printf("%d",ans);
return 0;
}
消消乐
对于弱化版,可以直接定义
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=350;
int n,ans;
int a[N],dp[N][N];
inline int read(){
char c=getchar();int f=1,x=0;
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int main(){
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
ans=max(ans,a[i]);
dp[i][i]=a[i];
}
for(int l=2;l<=n;l++){
for(int i=1;i+l-1<=n;i++){
int j=i+l-1;
for(int k=i;k<j;k++){
if(dp[i][k]!=0&&dp[i][k]==dp[k+1][j]){
dp[i][j]=max(dp[i][j],dp[i][k]+1);
ans=max(ans,dp[i][j]);
}
}
}
}
printf("%d",ans);
return 0;
}
但是对于加强版,
定义
所以状态转移方程就是:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+100;
int n,ans,x;
int f[60][N];
inline int read(){
char c=getchar();int f=1,x=0;
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int main(){
n=read();
for(int i=1;i<=n;i++){
x=read();
f[x][i]=i+1;
}
for(int i=2;i<=58;i++){
for(int j=1;j<=n;j++){
if(!f[i][j]) f[i][j]=f[i-1][f[i-1][j]];
if(f[i][j]) ans=max(ans,i);
}
}
printf("%d",ans);
return 0;
}
最长等差子序列
一开始想了一种暴力想法,用
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+100;
const int M=5e3+100;
int n,res;
int a[M],f[N];
set<int> dc;
set<int>::iterator p;
inline int read(){
char c=getchar();int f=1,x=0;
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int solve(int cha){
int ans=0;
for(int i=1;i<=n;i++) f[i]=1;
for(int i=2;i<=n;i++){
for(int j=1;j<i;j++){
if(a[i]-a[j]==cha) f[i]=max(f[i],f[j]+1);
}
}
for(int i=1;i<=n;i++) ans=max(ans,f[i]);
return ans;
}
int main(){
n=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<n;i++)for(int j=i+1;j<=n;j++) dc.insert(a[j]-a[i]);
for(p=dc.begin();p!=dc.end();p++){
int cha=*p;
res=max(res,solve(cha));
}
printf("%d",res);
return 0;
}
正解是定义二维数组,
不过由于数组下标不能为负数,但是题目又说了输入得数都是小于等于
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e3+100;
const int M=5e3+100;
int n,ans;
int a[M],f[M][N];
inline int read(){
char c=getchar();int f=1,x=0;
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int main(){
n=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++)for(int j=0;j<=N;j++) f[i][j]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
if(a[i]!=a[j]){
int cha=a[i]-a[j]+1000;
f[i][cha]=max(f[i][cha],f[j][cha]+1);
ans=max(ans,f[i][cha]);
}
}
}
printf("%d",ans);
return 0;
}
玩具取名
状压一下。
我们令
至于转移吗……劈开拼一起即可。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=210;
int n;
char s[N];
int m[4],tr[4][4],f[N][N];
inline int read(){
char c=getchar();int f=1,x=0;
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int pd(char x){
if(x=='W') return 0;
if(x=='I') return 1;
if(x=='N') return 2;
if(x=='G') return 3;
}
void print(){
if(f[1][n]&(1<<0)) printf("W");
if(f[1][n]&(1<<1)) printf("I");
if(f[1][n]&(1<<2)) printf("N");
if(f[1][n]&(1<<3)) printf("G");
if(!f[1][n]) printf("The name is wrong!");
}
int main(){
for(int i=0;i<4;i++) m[i]=read();
for(int i=0;i<4;i++){
for(int j=0;j<m[i];j++){
scanf("%s",s);
tr[pd(s[0])][pd(s[1])]|=(1<<i);
}
}
scanf("%s",s+1);
n=strlen(s+1);
for(int i=1;i<=n;i++) f[i][i]=(1<<pd(s[i]));
for(int l=2;l<=n;l++){
for(int i=1,j=i+l-1;j<=n;i++,j++){
for(int k=i;k<j;k++){
for(int a=0;a<4;a++){
for(int b=0;b<4;b++){
if(!(f[i][k]&(1<<a))) continue;
if(!(f[k+1][j]&(1<<b))) continue;
f[i][j]|=tr[a][b];
}
}
}
}
}
print();
return 0;
}
任务安排
观察到我们每在第
因此我们可以设
则有
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL INF=0x3f3f3f3f3f3f3f3f;
const LL N=5e3+100;
int n,s;
LL f[N],t[N],c[N];
inline LL read(){
char c=getchar();LL f=1,x=0;
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int main(){
n=read();
s=read();
memset(f,INF,sizeof(f));
f[0]=0;
for(int i=1;i<=n;i++){
t[i]=read();
c[i]=read();
t[i]+=t[i-1];
c[i]+=c[i-1];
}
for(int i=1;i<=n;i++){
for(int j=0;j<i;j++){
f[i]=min(f[i],f[j]+s*(c[n]-c[j])+t[i]*(c[i]-c[j]));
}
}
printf("%lld",f[n]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】