昨天放假了^_^
今天也只做了三题
感觉颓废了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);
}