牛客练习赛59(C 三分 E 线段树上合并dp)

题目链接

C-装备合成

题意:

做法:

我也不知道为什么可以三分,至今没懂,题解就是这么说的,(你个嘚嘚)大概就是下面的方程会得到z的一个抛物线的图:

n1*(2a+3b)<=x  

n2*(4a+b)<=y

z=n1+n2

我的三分怎么写怎么wa,参考了题解的代码。。。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=2e5+10;
int x,y,mi,ans;

int cal(int num,int x,int y)
{
    return num+min((x-2*num)/4,y-3*num);

}
int main()
{
    int _;cin>>_;while(_--)
    {
        scanf("%d%d",&x,&y);

        int l=0,r=min(x/2,y/3),ans;
        while(l+10<=r)
        {
            int m1=l+r>>1,m2=m1+r>>1;
            if(cal(m1,x,y)>=cal(m2,x,y)) r=m2-1,ans=m1;
            else l=m1+1;
        }
        int m1=ans;

        //printf("m1:%d\n",m1+min(x-2*mi,y-3*mi));

        int res=0;
        for(int i=l;i<=r;i++)
        res=max(res,i+min((x-2*i)/4,y-3*i));

        printf("%d\n",res);
    }
}

E-石子搬运

扫描二维码关注公众号,回复: 10150389 查看本文章

想到dp[i][j]为i堆石头 搬j次的最小花费,再想到两两合并没有先后顺序,所以就可以采用线段树合并dp即可

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=4e2+10;
ll dp[4*N][N];
ll n,m,a[N],len[4*N];
ll sum=0;
void push(int id)
{
    memset(dp[id],0x3f3f3f3f,sizeof(dp[id]));
    int ls=id<<1,rs=id<<1|1;
    for(int i=len[ls];i<=m;++i){
        for(int j=len[rs];i+j<=m;++j){
            dp[id][i+j]=min(dp[id][i+j],dp[ls][i]+dp[rs][j]);
        }
    }
}
void build(int id,int l,int r)
{
    len[id]=r-l+1;
    if(l==r){
        for(int i=1;i<=min(a[l],m);++i){
            ll v=a[l]/i;
            dp[id][i]=a[l]%i*(v+1)*(v+1)+(i-a[l]%i)*v*v;
        }
        return ;
    }
    int mid=l+r>>1;
    build(id<<1,l,mid);
    build(id<<1|1,mid+1,r);
    push(id);
}
void up(int id,int l,int r,int pos,ll v)
{
    if(l==r){
        a[l]=v;
        memset(dp[id],0x3f3f3f3f,sizeof(dp[id]));
        for(int i=1;i<=min(a[l],m);++i){
            ll v=a[l]/i;
            dp[id][i]=a[l]%i*(v+1)*(v+1)+(i-a[l]%i)*v*v;
        }
        return ;
    }
    int mid=l+r>>1;
    if(pos<=mid) up(id<<1,l,mid,pos,v);
    else up(id<<1|1,mid+1,r,pos,v);
    push(id);
}
int main()
{
    cin>>n>>m;
    rep(i,1,n) {
        scanf("%lld",&a[i]);
        sum+=a[i];
    }
    memset(dp,0x3f3f3f3f,sizeof(dp));
    build(1,1,n);
    int q;
    scanf("%d",&q);
    while(q--)
    {
        int id;
        ll v;
        scanf("%d%lld",&id,&v);
        sum=sum-a[id]+v;
        up(1,1,n,id,v);
        printf("%lld\n",dp[1][min(sum,m)]);
    }
}
发布了498 篇原创文章 · 获赞 66 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_41286356/article/details/104852201