区间DP day42

昨天放假了^_^

今天也只做了三题

感觉颓废了ww

不过今天认识很多大一牌爷orz

明天能以他们为目标好好努力嘛

不过今天从ygg哪里学到了dp的一些理解

我们状态表示时 要完备 要不重不漏的每一个情况都算到

并且我们中间的操作 也要以状态表示为基础顺序来做

不然肯定是会出差错的

1068. 环形石子合并

我超今天我才知道我是第二重循环写错了

平常都是写的三重循环水过去

其实我们只要右端点不超过n《1 就可以了

#include <bits/stdc++.h>
using namespace std;
const int N = 410;
const int M = 1<<12;
const int mod = 1e9+7;
#define int long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
int f[N][N],s[N];
signed main(){
    fast
    int n;cin>>n;
    int a[N];
    for(int i=1;i<=n;i++)cin>>a[i],a[i+n]=a[i];
    for(int i=1;i<=n<<1;i++)s[i]=s[i-1]+a[i];
    int res=inf;
    memset(f,0x3f3f,sizeof f);
    for(int i=1;i<=2*n;i++)f[i][i]=0;
    for(int len=2;len<=n;len++){
        for(int i=1,j=i+len-1;j<=n<<1;i++,j++){
            for(int k=i;k<j;k++){
                f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+s[j]-s[i-1]);
                if(len==n)res=min(res,f[i][j]);
            }
        }
    }
    cout<<res<<endl;
    memset(f,0,sizeof f);
    int ans=0;
    for(int len=2;len<=n;len++){
        for(int i=1,j=i+len-1;j<=n<<1;i++,j++){
            for(int k=i;k<j;k++){
                f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+s[j]-s[i-1]);
                ans=max(ans,f[i][j]);
            }
        }
    }
    cout<<ans<<endl;
    return ~~(0^_^0);
}

AcWing 1069. 凸多边形的划分

我们找到一个分界点(最重要的就是

然后我们就可以很快得到状态表示就是

f_i_j 表示的是 i点到j的min

然后就可以分治来做了

高精度麻烦点(贴板子就行了

注意不要整inf了 直接empty inf 肯定没有高精度大啊

#include <bits/stdc++.h>
using namespace std;
const int N = 410;
const int M = 1<<12;
const int mod = 1e9+7;
#define int long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
vector<int>f[N][N];
int n,w[N];
bool cmp(vector<int> &a, vector<int> &b)
{
    if (a.size() != b.size()) return a.size() < b.size();
    for (int i = a.size() - 1; i >= 0; i -- )
        if (a[i] != b[i])
            return a[i] < b[i];
    return true;
}
vector<int> add(vector<int> a, vector<int> b)
{
    vector<int> c;
    int t = 0;
    for (int i = 0; i < a.size() || i < b.size(); i ++ )
    {
        if (i < a.size()) t += a[i];
        if (i < b.size()) t += b[i];
        c.push_back(t % 10);
        t /= 10;
    }
    while (t) c.push_back(t % 10), t /= 10;
    return c;
}
vector<int> mul(vector<int> a, int b)
{
    vector<int> c;
    int t = 0;
    for (int i = 0; i < a.size(); i ++ )
    {
        t += b * a[i];
        c.push_back(t % 10);
        t /= 10;
    }
    while (t) c.push_back(t % 10), t /= 10;
    return c;
}
signed main(){
    fast
    cin>>n;
    for(int i=1;i<=n;i++)cin>>w[i];
    for(int len=3;len<=n;len++){
        for(int i=1,j=len+i-1;j<=n;i++,j++){
            for(int k=i+1;k<j;k++){
                auto new_val = mul(mul({w[i]}, w[k]), w[j]);
                new_val = add(add(new_val, f[i][k]), f[k][j]);
                if (f[i][j].empty() || cmp(new_val, f[i][j])) f[i][j] = new_val;
            }
        }
    }
    for(int i=f[1][n].size()-1;i>=0;i--)cout<<f[1][n][i];
    return ~~(0^_^0);
}

321. 棋盘分割

五维确实想对了 状态表示想过正解 可是不知道咋写 感觉推不过去

而正解也没推状态表示 而是直接的记忆化搜索 这何尝不是一种取舍

可是此题要求一个min值

我们只好先初始化成一个极小值 让后进去避过记忆化搜索返回时再初始化为一个很大的值

#include <bits/stdc++.h>
using namespace std;
const int N = 16;
const int M = 1<<12;
const int mod = 1e9+7;
#define int long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
double f[N][N][N][N][N];
int n,s[N][N];
double X;
double get(int x1,int y1,int x2,int y2){
    double sum=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]-X;
    return sum*sum/n;
}
double dp(int x1,int y1,int x2,int y2,int k){
    auto &v=f[x1][y1][x2][y2][k];
    if(v>=0)return v;
    if(k==1)return v=get(x1,y1,x2,y2);
    v=1e9;
    for(int i=x1;i<x2;i++){
        v=min(v,dp(x1,y1,i,y2,k-1)+get(i+1,y1,x2,y2));
        v=min(v,dp(i+1,y1,x2,y2,k-1)+get(x1,y1,i,y2));
    }
    for(int i=y1;i<y2;i++){
        v=min(v,dp(x1,y1,x2,i,k-1)+get(x1,i+1,x2,y2));
        v=min(v,dp(x1,i+1,x2,y2,k-1)+get(x1,y1,x2,i));
    }
    return v;
}
signed main(){
    fast
    cin>>n;
    for(int i=1;i<=8;i++){
        for(int j=1;j<=8;j++){
            cin>>s[i][j];
            s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
        }
    }
    X=(double)s[8][8]/(double)n;
    memset(f,128,sizeof f);
    printf("%.3lf",sqrt(dp(1,1,8,8,n)));
    return ~~(0^_^0);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值