数字游戏
这是一个很好的区间dp题,个人感觉,容易想到,但是不容易写出来,边界处理很强,预处理出,前缀和,最小值需要初始化,破坏环成为两倍的大小的数组,细节很多。
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
#include<deque>
#include<map>
#include<stdlib.h>
#include<set>
#include<iomanip>
#include<stack>
#define ll long long
#define ms(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x & -x
#define fi first
#define ull unsigned long long
#define se second
#define endl "\n"
#define bug cout<<"----acac----"<<endl
#define IOS ios::sync_with_stdio(false), cin.tie(0),cout.tie(0)
using namespace std;
const int maxn =1e5 + 5;
const int maxm = 1.5e5+50;
const double eps = 1e-7;
const double inf = 0x3f3f3f3f;
const double lnf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
const int p=1e7+233;
const double pi=3.141592653589;
int dpma[105][105][12],dpmi[105][105][12];
int a[105];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i+n]=a[i];//破坏环
}
ms(dpmi,inf);
for(int i=2;i<=2*n;i++)a[i]+=a[i-1];//前缀和
for(int i=1;i<=2*n;i++)
{
for(int j=i;j<=2*n;j++)
{
dpma[i][j][1]=dpmi[i][j][1]=((a[j]-a[i-1])%10+10)%10;//预处理
}
}
for(int i=2;i<=m;i++)//枚举断点个数
{
for(int l=1;l<=2*n;l++)//左端点
{
for(int r=l+i-1;r<=2*n;r++)//右端点
{
for(int k=l+i-2;k<r;k++)//枚举断点位置
{
dpma[l][r][i]=max(dpma[l][k][i-1]*(((a[r]-a[k])%10+10)%10),dpma[l][r][i]);
dpmi[l][r][i]=min(dpmi[l][k][i-1]*(((a[r]-a[k])%10+10)%10),dpmi[l][r][i]);
}
}
}
}
int ma=0,mi=inf;
for(int i=1;i<=n;i++)
{
ma=max(ma,dpma[i][i+n-1][m]);
mi=min(mi,dpmi[i][i+n-1][m]);
}
printf("%d\n%d\n",mi,ma);
return 0;
}
通过这个题我学到许多,这种路径压缩是真的强,放在我是想不到,我想的是离散,然而离散的话就不好控制特么之间的距离,路径压缩我感觉是离散的一种拓展,和离散十分的相似(个人感觉)
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
#include<deque>
#include<map>
#include<stdlib.h>
#include<set>
#include<iomanip>
#include<stack>
#define ll long long
#define ms(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x & -x
#define fi first
#define ull unsigned long long
#define se second
#define endl "\n"
#define bug cout<<"----acac----"<<endl
#define IOS ios::sync_with_stdio(false), cin.tie(0),cout.tie(0)
using namespace std;
const int maxn =1e5 + 5;
const int maxm = 1.5e5+50;
const double eps = 1e-7;
const double inf = 0x3f3f3f3f;
const double lnf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
const double pi=3.141592653589;
int a[105],flage[maxn],dp[maxn];//看好空间大小啊
int main()
{
int L;
int S,T,M;
scanf("%d%d%d%d",&L,&S,&T,&M);
if(S==T)//一定要特判啊
{
int x,cnt=0;
for(int i=1;i<=M;i++)
{
scanf("%d",&x);
cnt+=(x%S==0);
}
printf("%d\n",cnt);
return 0;
}
for(int i=1;i<=M;i++)
{
scanf("%d",&a[i]);
}
sort(a+1,a+1+M);
a[M+1]=L;
ms(dp,inf);
dp[0]=0;
a[0]=0;
int p=0;
for(int i=1;i<=M;i++)
{
int far=min(90,a[i]-a[i-1]);//如果想看证明过程的话请到洛谷去看,可以通过上面的链接进入,也可以自己去搜索,进去后第一个题解有详细证明过程。其实只要开到(T+1)*T-T-(T+1)也就是71就足够了
p+=far;
flage[p]=1;
}
p+=min(90,L-a[M]);
for(int i=0;i<=p+T-1;i++)
{
for(int j=S;j<=T;j++)
{
if(i-j>=0)
dp[i]=min(dp[i],dp[i-j]+flage[i]);
}
}
int ans=inf;
for(int i=p;i<=p+T-1;i++)//因为你可能是条过了桥,可能从L-1跳到L-1+(S到T内的一个数),也可能是l-2+(S到K内的一个数),所以答案在p到p+T-1内
{
ans=min(ans,dp[i]);
}
printf("%d\n",ans);
return 0;
}
本题主要是要想到把位移与休息和跑步分开分别求一次dp,这样就十分简单了
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
#include<deque>
#include<map>
#include<stdlib.h>
#include<set>
#include<iomanip>
#include<stack>
#define ll long long
#define ms(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x & -x
#define fi first
#define ull unsigned long long
#define se second
#define endl "\n"
#define bug cout<<"----acac----"<<endl
#define IOS ios::sync_with_stdio(false), cin.tie(0),cout.tie(0)
using namespace std;
const int maxn =3e5 + 5;
const int maxm = 1.5e5+50;
const double eps = 1e-7;
const double inf = 0x3f3f3f3f;
const double lnf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
const double pi=3.141592653589;
int dp[maxn];
int main()
{
int m,s,t;
scanf("%d%d%d",&m,&s,&t);
for(int i=1;i<=t;i++)
{
if(m>=10)
dp[i]=dp[i-1]+60,m-=10;
else
m+=4,dp[i]=dp[i-1];
}
for(int i=1;i<=t;i++)
{
dp[i]=max(dp[i],dp[i-1]+17);
}
if(dp[t]<s)
{
printf("No\n%d\n",dp[t]);
}
else
{
printf("Yes\n");
for(int i=1;i<=t;i++)
{
if(dp[i]>=s)
{
printf("%d\n",i);
return 0;
}
}
}
return 0;
}
没想到这么容易的一个题目我看题解都看了半天,我也是醉了,还是不喜欢独立思考啊,这毛病要改啊,
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
#include<deque>
#include<map>
#include<stdlib.h>
#include<set>
#include<iomanip>
#include<stack>
#define ll long long
#define ms(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x & -x
#define fi first
#define ull unsigned long long
#define se second
#define endl "\n"
#define bug cout<<"----acac----"<<endl
#define IOS ios::sync_with_stdio(false), cin.tie(0),cout.tie(0)
using namespace std;
const int maxn =3e5 + 5;
const int maxm = 1.5e5+50;
const double eps = 1e-7;
const double inf = 0x3f3f3f3f;
const double lnf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
const double pi=3.141592653589;
int dp[maxn],n,a[maxn],f[maxn];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
int ma=1;
for(int i=1;i<=n;i++)
{
dp[i]=1;
for(int j=1;j<i;j++)
{
if(a[i]<a[j])
{
dp[i]=max(dp[i],dp[j]+1);
ma=max(ma,dp[i]);
}
}
}
for(int i=1;i<=n;i++)
{
if(dp[i]==1)f[i]=1;
for(int j=1;j<i;j++)
{
if(dp[i]==dp[j]+1&&a[i]<a[j])//如果dp[j]+1==dp[i]并且a[i]<a[j],那么a[j]一定可以链接上a[i]成为长度位dp[i],所以加起来
{
f[i]+=f[j];
}
else if(dp[i]==dp[j]&&a[i]==a[j])//如果两个都相等的话舍弃一个对结果没有影响
f[j]=0;
}
}
int sum=0;
for(int i=1;i<=n;i++)
{
if(dp[i]==ma)sum+=f[i];
}
printf("%d %d\n",ma,sum);
return 0;
}