SRM 658 DIV1 650 二分答案 动态规划

来源:互联网 发布:白岩松事件犯众怒知乎 编辑:程序博客网 时间:2024/06/07 07:30

题目链接:暂无

题目大意:
n个数,每次操作可以选择3个数,将其中一个数减9,一个数减3,一个数减1,不能减同一个数,询问最少多少次操作可以令所有数0

题解:
二分枚举答案lim,那么就可以将操作拆分来看,有lim次减9操作,lim次减3操作,lim次减1操作,但是对于某个数的总操作次数不能大于lim(此时这个数一定在某次操作中被同时被减)
f[i][A][B]表示已经将i1个数减为非正数,还能用A次减9操作,B次减3操作时剩余的最大的减1操作的次数
那么f[i][A][B]=max{f[i1][A+a][B+b]c}(将第i个数减为非正用了a次减9操作,b次减3操作,c次减1操作)
如果A,B0使得f[n][A][B]0那么lim可行

代码:

#include <bits/stdc++.h>using namespace std;class Mutalisk{    private:    int n;    int f[21][94][94];        bool Judge(const vector<int>&x,int lim)        {            memset(f,-1,sizeof f);            f[0][lim][lim]=lim;            for(int i=1;i<=n;i++)                for(int A=0;A<=lim;A++)                for(int B=0;B<=lim;B++)                    if(dp[i-1][A][B]>=0)                        for(int a=0;a<=A;a++)                        for(int b=0;b<=B;b++)                        {                            int c=max(0,x[i-1]-a*9-b*3);                            if(a+b+c>lim) continue;                            if(c>f[i-1][A][B]) continue;                            f[i][A-a][B-b]=max(f[i][A-a][B-b],f[i-1][A][B]-c);                        }            for(int A=0;A<=lim;A++)            for(int B=0;B<=lim;B++)                if(f[n][A][B]>=0)                    return 1;            return 0;        }    public:        int minimalAttacks(vector<int>x)        {            n=x.size();            int l=1,r=93,re,mid;            while(l<=r)            {                mid=(l+r)>>1;                if(Judge(x,mid))                {                    re=mid;                    r=mid-1;                }                else l=mid+1;            }            return re;        }};
0 0
原创粉丝点击