疯狂刷dp中

数字游戏
这是一个很好的区间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;
}

P1052 过河

通过这个题我学到许多,这种路径压缩是真的强,放在我是想不到,我想的是离散,然而离散的话就不好控制特么之间的距离,路径压缩我感觉是离散的一种拓展,和离散十分的相似(个人感觉)

#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;
}

P1099 树网的核

本题主要是要想到把位移与休息和跑步分开分别求一次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;
}

P1108 低价购买

没想到这么容易的一个题目我看题解都看了半天,我也是醉了,还是不喜欢独立思考啊,这毛病要改啊,

#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;
}

猜你喜欢

转载自blog.csdn.net/qcccc_/article/details/107849564
今日推荐