2021牛客暑期多校训练营5(B.期望 G.暴力)

这场感觉需要记录的东西貌似不是很多,所以写个总的。

B.Boxes

根据贪心原则,其实我们可以注意到两点:
1、是否要提示是开始前决定的。要么,你一开始不要提示,全部盒子都开一次。要么,先要提示,根据提示的数量开盒子。因为假若你中途再要提示,可能要到后发现盒子开多了,还不如一开始就要,花费只多不少。
2、要了提示后,你一定是按照盒子价值从小到大开的。因为你开一个盒子都是的概率白或黑,因此从总体来说,从小往大开的话,期望的花费会比较少(可以往下看看期望的计算自己思考下)。
显然,如果不要提示,则期望为
若要提示,则就要分情况了。
因为有了提示,你就知道有几个白几个黑,这时候,你会在中途因为开够数量而停下来。我们将研究对象转为每个盒子,则,假设有x个白/黑盒子,我们可以想到第i个盒子被开到的概率其实相当于最后一个白/黑盒子的位置>=i
现在考虑如何计算这个概率。假设从正面进行计算,我貌似没想出来,有知道的大佬麻烦说下Orz,这里采用对立事件,我们算下开不到这个箱子的概率。

若开不到,则说明箱子全部在前面的i-1个位置上。这个好算:


(注意下要算黑白两种,要*2)

所以,第i个箱子被开到的概率是:


根据定义算即可。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define IOS                       \
    ios_base::sync_with_stdio(0); \
    cin.tie(0);
#define rep(i, a, n) for (int i = a; i <= n; ++i)
#define per(i, a, n) for (int i = n; i >= a; --i)
//#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
int mod = 1e9 + 7;
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}

template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
int gcd(int a, int b)
{
    return b == 0 ? a : gcd(b, a % b);
}
int lcm(int a, int b) { return a / gcd(a, b) * b; };
ll ksm(ll a, ll n)
{
    ll ans = 1;
    while (n)
    {
        if (n & 1)
            ans = (ans * a) % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return ans % mod;
}
//==============================================================
const int maxn=1e5+10;
int n;
double c,w[maxn];
double Pow[maxn];

int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    //clock_t c1 = clock();
    //===========================================================
    read(n);cin>>c;  
    Pow[0]=1;
    for(int i=1;i<maxn;++i)Pow[i]=Pow[i-1]/2;
    double ans1=0;
    for(int i=1;i<=n;++i)cin>>w[i],ans1+=w[i];
    double ans2=c;
    sort(w+1,w+1+n);
    for(int i=1;i<n;++i){
       // cerr<<(1-2*Pow[n-i+1])<<" "<<w[i]<<endl;
        ans2+=(1-Pow[n-i])*w[i];
    }
    //cerr<<ans2<<endl;
    printf("%.10lf\n",min(ans1,ans2));;
    //===========================================================
    //std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
    return 0;
}

G.Greater Integer, Better LCM

这题其实主体思路不难想。他给出的是两个数的lcm,我们都知道,lcm是两个数的质因子分解的次数求max,因此,我们可以考虑枚举让(a+x)和(b+y)哪个数在该质因子上的次数是max。例如,对于样例中所给的,我们可以考虑是(a+x)的因子,或者是(b+y)的因此,同理。由于这题给的数很小,我们就可以冲了。然后T了。。。
但是,数这么小,所以还是考虑剪枝。这里参考了rank5的代码,三处剪枝,这里不多说,我写在注释里。
这题我认为关键是掌握好利用lcm是两个数质因子次数取max的性质。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define IOS                       \
    ios_base::sync_with_stdio(0); \
    cin.tie(0);
#define rep(i, a, n) for (int i = a; i <= n; ++i)
#define per(i, a, n) for (int i = n; i >= a; --i)
//#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
int mod = 1e9 + 7;
template<typename T>void write(T x) {
    if(x<0) { putchar('-'); x=-x; }
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
namespace FastIO {
    const int SIZE = 1 << 16;
    char buf[SIZE], str[64];
    int l = SIZE, r = SIZE;
    int read(char *s) {
        while (r) {
            for (; l < r && buf[l] <= ' '; l++);
            if (l < r) break;
            l = 0, r = int(fread(buf, 1, SIZE, stdin));
        }
        int cur = 0;
        while (r) {
            for (; l < r && buf[l] > ' '; l++) s[cur++] = buf[l];
            if (l < r) break;
            l = 0, r = int(fread(buf, 1, SIZE, stdin));
        }
        s[cur] = '\0';
        return cur;
    }
    template<typename type>
    bool read(type &x, int len = 0, int cur = 0, bool flag = false) {
        if (!(len = read(str))) return false;
        if (str[cur] == '-') flag = true, cur++;
        for (x = 0; cur < len; cur++) x = x * 10 + str[cur] - '0';
        if (flag) x = -x;
        return true;
    }
    template <typename type>
    type read(int len = 0, int cur = 0, bool flag = false, type x = 0) {
        if (!(len = read(str))) return false;
        if (str[cur] == '-') flag = true, cur++;
        for (x = 0; cur < len; cur++) x = x * 10 + str[cur] - '0';
        return flag ? -x : x;
    }
} using FastIO::read;
int gcd(int a, int b)
{
    return b == 0 ? a : gcd(b, a % b);
}
int lcm(int a, int b) { return a / gcd(a, b) * b; };
ll ksm(ll a, ll n)
{
    ll ans = 1;
    while (n)
    {
        if (n & 1)
            ans = (ans * a) % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return ans % mod;
}
//==============================================================
const int maxn=25+10;
using i128=__int128_t;
i128 ans;
i128 p[maxn],q[maxn];
i128 pre[maxn][maxn];
i128 suf[maxn];
int n;
i128 a,b,c;

void dfs(int pos,i128 A,i128 B){
    if(A*suf[pos]<a||B*suf[pos]<b)return ;//剪枝1:不可能满足条件,剪掉。
    if(A-a+B-b>ans)return;//剪枝1:不可能比现有答案优,剪掉。
    if(pos>n){
        if(A<a||B<b)return ;
        ans=min(ans,A-a+B-b);
        return ;
    }
    i128 now=1;
    for(int i=1;i<=q[pos];++i){
        dfs(pos+1,A*now,B*pre[pos][q[pos]]);
        dfs(pos+1,A*pre[pos][q[pos]],B*now);
        now*=p[pos];
    }
    dfs(pos+1,A*pre[pos][q[pos]],B*pre[pos][q[pos]]);//剪枝3:这个就有点那个啥了,,减少了一次重复的搜索,但不加就会T
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    //clock_t c1 = clock();
    //===========================================================
    read(n);
    for(int i=1;i<=n;++i)read(p[i]),read(q[i]);
    read(a),read(b);
    for(int i=1;i<=n;++i){
        pre[i][0]=1;
        for(int j=1;j<=q[i];++j){
            pre[i][j]=pre[i][j-1]*p[i];
        }
    }
    suf[n+1]=1;
    for(int i=n;i>=1;--i){
        suf[i]=suf[i+1]*pre[i][q[i]];
    }
    //init();
    c=1;
    for(int i=1;i<=n;++i)c*=pre[i][q[i]];
    ans=2*c;
    dfs(1,1,1);
    write(ans);
    //===========================================================
    //std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
    return 0;
}

但这个做法我认为还不算完美Orz(?),之后再考虑学(抄)习(袭)其他的代码找找更好的解***再更新(大概?)

全部评论
请问第一个剪枝为什么
点赞 回复 分享
发布于 2021-08-01 21:03

相关推荐

03-15 14:55
已编辑
门头沟学院 golang
bg:双非学院本&nbsp;ACM银&nbsp;go选手timeline:3.1号开始暑期投递3.7号第二家公司离职顽岩科技&nbsp;ai服务中台方向&nbsp;笔试➕两轮面试,二面挂(钱真的好多😭)厦门纳克希科技&nbsp;搞AI的,一面OC猎豹移动&nbsp;搞AIGC方向&nbsp;一面OC北京七牛云&nbsp;搞AI接口方向&nbsp;一面OC上海古德猫宁&nbsp;搞AIGC方向&nbsp;二面OC上海简文&nbsp;面试撞了直接拒深圳图灵&nbsp;搞AIGC方向一面后无消息懒得问了,面试官当场反馈不错其他小厂没记,通过率80%,小厂杀手😂北京字节&nbsp;具体业务不方便透露也是AIGC后端方向2.28约面&nbsp;(不知道怎么捞的我,我也没在别的地方投过字节简历哇)3.6一面&nbsp;一小时&nbsp;半小时拷打简历(主要是AIGC部分)剩余半小时两个看代码猜结果(经典go问题)➕合并二叉树(秒a,但是造case造了10分钟哈哈)一天后约二面3.12&nbsp;二面,让我挑简历上两个亮点说,主要说的docker容器生命周期管理和raft协议使用二分法优化新任leader上任后与follower同步时间。跟面试官有共鸣,面试官还问我docker底层cpu隔离原理和是否知道虚拟显存。之后一道easy算法,(o1空间解决&nbsp;给定字符串含有{和}是否合法)秒a,之后进阶版如何用10台机加快构建,想五分钟后a出来。面试官以为45分钟面试时间,留了18分钟让我跟他随便聊,后面考了linux&nbsp;top和free的部分数据说什么意思(专业对口了只能说,但是当时没答很好)。因为当时手里有7牛云offer,跟面试官说能否快点面试,马上另外一家时间到了。10分钟后约hr面3.13,上午hr面,下午走完流程offer到手3.14腾讯技术运营约面,想直接拒😂感受:&nbsp;因为有AIGC经验所以特别受AI初创公司青睐,AIGC后端感觉竞争很小(指今年),全是简历拷打,基本没有人问我八股(八股吟唱被打断.jpeg),学的东西比较广的同时也能纵向深挖学习,也运气比较好了哈哈可能出于性格原因,没有走主流Java路线,也没有去主动跟着课写项目,项目都是自己研究和写的哈哈
烤点老白薯:你根本不是典型学院本的那种人,贵了你这能力
查看7道真题和解析
点赞 评论 收藏
分享
大摆哥:刚好要做个聊天软件,直接让你帮他干活了
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务