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

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(?),之后再考虑学(抄)习(袭)其他的代码找找更好的解***再更新(大概?)