CF1599

CF1599

Bubble Cup 14 - Finals Online Mirror (Unrated, ICPC Rules, Teams Preferred, Div. 1)

CF1599A

link

题意

给你一个长度为 \(N\) 的质量为 \(A_1,A_2,\dots,A_N\) 的数组 \(A\)。每个数组中的值表示各个砝码的重量。

所有砝码的质量均不相同。你可以把每个砝码放在天平的一边(左边或右边)。

你不必按照 \(A_1,\dots,A_N\) 的顺序放置砝码。还有一个由字符 \(\texttt{L}\)\(\texttt{R}\) 组成的字符串 \(S\),意思是在放完第 \(i\) 个砝码(不是 \(A_i\) ,而是选择第 \(i\) 个砝码)后,天平的左边或右边应该更重。

找出在天平上放置砝码的顺序,以便满足字符串 \(S\) 的规则。

\(n \le 2\times 10^5\)

题解

很神仙的思路。

首先发现样例中没有 \(-1\),猜测一定有解。

然后就相当于给出一个构造方案。

数组顺序没有影响,直接排序。

考虑倒着做,将每次填入一个数变成每次删除一个数。

有一个大胆的想法:初始状态让两个天平交替填入 \(1,2,\dots,n\)

然后发现,每次拿出全局最小值一定不影响倾斜方向,拿出全局最大值一定影响倾斜方向。

证明显然。

然后就做完了()

代码

#include<bits/stdc++.h>
using namespace std;
bool stmemory;
namespace Call_me_Eric{
inline int read(){
    int x = 0, f = 1;char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
    return x * f;
}
const int maxn = 2e5 + 10;
int n;
int a[maxn];
char ch[maxn];
bool flag[maxn];//1 = L, 0 = R;
deque<int> L,R;
pair<int,char> ans[maxn];
void main(){
    n = read();
    for(int i = 1;i <= n;i++)a[i] = read();
    scanf("%s",ch + 1);sort(a + 1,a + 1 + n);
    for(int i = 1;i <= n;i++){
        flag[i] = ch[i] == 'L';
        if(i & 1){L.push_back(a[i]);}
        else {R.push_back(a[i]);}
    }
    if(flag[n] != (n & 1)){swap(L,R);}
    for(int i = n;i >= 1;i--){
        int flg = flag[i] ^ flag[i - 1];
        pair<int,char> ll,rr;
        ll = rr = make_pair(flg ? -0x3f3f3f3f : 0x3f3f3f3f, 'O');
        if(L.size()){ll = make_pair(flg ? L.back() : L.front(),'L');}
        if(R.size()){rr = make_pair(flg ? R.back() : R.front(),'R');}
        if((ll < rr) ^ flg){ans[i] = ll;if(flg)L.pop_back();else L.pop_front();}
        else {ans[i] = rr;if(flg)R.pop_back();else R.pop_front();}
    }
    for(int i = 1;i <= n;i++){printf("%d %c\n",ans[i].first, ans[i].second);}
    return;
}
};
bool edmemory;
signed main(){
    auto stclock = clock();
    Call_me_Eric::main();
    auto edclock = clock();
    cerr << (&stmemory - &edmemory) / 1024.0 / 1024.0 << " Mib cost.\n";
    cerr << (edclock - stclock) * 1.0 / CLOCKS_PER_SEC << " Sec cost.\n";
    return 0;
}

CF1599C

link

题意

你和你的对手一起玩一个游戏,该游戏共有 \(n\) 张地图,系统会先从中随机选择 \(3\) 张,你和你的对手需要各自从中选择一张删去(可以相同),系统会在剩下的若干张中随机选一张作为本次游戏的地图

为了赢得更多的胜利,你想预先学习一些地图。但是由于时间有限,你希望学习尽量少的地图,并且满足每次玩到自己学习过的地图的概率至少为 \(p\)。请问满足条件最少需要学习的地图数是多少。对手不知道你预习了哪些地图。

\(n\le 10^3,p\in[0,1]\)

题解

分类讨论+水题。

枚举现在学习过了 \(i\) 个地图,考虑概率是否超过 \(p\)

四种情况:

  • 选到三个没学过的地图:情况数 \(n-i\choose 3\),没有能够赢的方法。
  • 选到两个没学过的地图:情况数 \({n-i\choose 2}\times i\times 3\)(剩余的一个学过的地图有三个位置可以放),有 \(\frac{1}{2}\) 的概率最终选择自己知道的地图。
  • 选到一个没学过的地图:情况数 \({i\choose 2}\times n-i\times 3\)(同理),只要自己禁掉不会的那张地图就一定都是会的,概率是 \(1\)
  • 选到零个没学过的地图:情况数 \({i\choose 3}\),不管怎么禁用都是知道的,概率是 \(1\)

然后除以总情况数 \(n\choose 3\) 即可。

代码

#include<bits/stdc++.h>
using namespace std;
bool stmemory;
namespace Call_me_Eric{
inline int read(){
    int x = 0, f = 1;char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
    return x * f;
}
const int maxn = 1e3 + 10;
int n;double p;
void main(){
    scanf("%d%lf",&n,&p);
    for(int i = 0;i <= n;i++){
        double ans = 0;
        if(i >= 1 && n - i >= 2)ans += 3.0 * (i) * (n - i) * (n - i - 1) * 0.5;
        if(i >= 2 && n - i >= 1)ans += 3.0 * (i) * (i - 1) * (n - i) * 1;
        if(i >= 3 && n - i >= 0)ans += (i) * (i - 1) * (i - 2) * 1;
        // printf("i = %d, ans = %lf\n",i,ans / n / (n - 1) / (n - 2));
        if(ans >= p * (n) * (n - 1) * (n - 2)){
            printf("%d\n",i);break;
        }
    }
    return;
}
};
bool edmemory;
signed main(){
    auto stclock = clock();
    Call_me_Eric::main();
    auto edclock = clock();
    cerr << (&stmemory - &edmemory) / 1024.0 / 1024.0 << " Mib cost.\n";
    cerr << (edclock - stclock) * 1.0 / CLOCKS_PER_SEC << " Sec cost.\n";
    return 0;
}

CF1599F

link

题意

给定长度为 \(n\) 的序列 \(a=[a_1,a_2,\cdots,a_n]\)。每次询问区间 \([l, r]\) 内的元素能否重排为模 \(10^9+7\) 意义下的公差为 \(d\) 的等差数列。

数据保证 \(1\le n,q\le 2\times 10^5\)\(0\le a_i<10^9+7\),对于每组询问 \(1\le l_i\le r_i\le n\)\(0\le d_i<10^9+7\)

题解

一下子想到这道题P3792 由乃与大母神原型和偶像崇拜

然后由于这道题有取模所以没办法用 \(gcd\) 判定。

那就用 \(k\) 次幂和。

不难发现,对于区间 \([l,r]\),公差是 \(d\) 的等差数列,如果设首项是 \(a\),那么有

\[\sum_{i=0}^{r-l}(a+di)=\sum_{i=l}^rarr_i \]

不难求出首项 \(a\)

然后要判定 \(k\) 次幂仍然是对的。

\[\sum_{i=0}^{r-l}(a+di)^k=\sum_{i=l}^r{arr_i}^k \]

右边的式子是好求的。

左边的式子不好求,考虑二项式定理:

\[\sum_{i=0}^{r-l}(a+di)^k\\ \iff \sum_{i=0}^{r-l}\sum_{j=0}^ka^{k-j}(di)^{j}\\ \iff \sum_{j=0}^ka^{k-j}d^{j}\sum_{i=0}^{r-l}i^{j}\\ \]

然后 \(\sum_{i=0}^{r-l}i^{j}\) 可以预处理。

然后就可以 \(O(k)\) 的计算这个式子。

然后就没了。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
bool stmemory;
namespace Call_me_Eric{
inline int read(){
    int x = 0, f = 1;char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
    return x * f;
}
const int maxn = 2e5 + 10, mod = 1e9 + 7, maxk = 10;
int n, q;
int arr[maxn];
int sum[maxk + 1][maxn];
int fac[maxk + 1][maxn];
int C[maxk + 1][maxk + 1];
int qpow(int x,int a){
    int res = 1;
    while(a){
        if(a & 1)res = res * x % mod;
        x = x * x % mod;a >>= 1;
    }
    return res;
}
int calc(int a,int d,int len,int k){
    int ans = 0;
    for(int j = 0;j <= k;j++){
        ans = (ans + (C[k][j] * qpow(a,k - j) % mod * qpow(d,j) % mod * fac[j][len - 1] % mod)) % mod;
    }
    return ans;
}
void main(){
    n = read(); q = read();
    C[0][0] = 1;
    for(int i = 1;i <= maxk;i++){C[i][0] = 1;for(int j = 1;j <= i;j++)C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;}
    fac[0][0] = 1;
    for(int i = 1;i <= n;i++){
        arr[i] = read(); sum[0][i] = 1; fac[0][i] = 1;
        for(int k = 1;k <= maxk;k++){sum[k][i] = sum[k - 1][i] * arr[i] % mod;fac[k][i] = fac[k - 1][i] * i % mod;}
        for(int k = 0;k <= maxk;k++){sum[k][i] = (sum[k][i] + sum[k][i - 1]) % mod;fac[k][i] = (fac[k][i] + fac[k][i - 1]) % mod;}
    }
    while(q--){
        int l = read(), r = read(), d = read();
        int sm = (sum[1][r] - sum[1][l - 1] + mod) % mod;
        int a = (sm - d * ((r - l) * (r - l + 1) / 2 % mod) % mod + mod) % mod * qpow(r - l + 1,mod - 2) % mod;
        bool flag = true;
        for(int k = 1;k <= maxk;k++)
            if((sum[k][r] - sum[k][l - 1] + mod) % mod != calc(a,d,r - l + 1,k)){
                // printf("k = %lld,a = %lld\n",k,a);
                flag = false;break;
            }
        puts(flag ? "Yes" : "No");
    }
    return;
}
};
bool edmemory;
signed main(){
    auto stclock = clock();
    Call_me_Eric::main();
    auto edclock = clock();
    cerr << (&stmemory - &edmemory) / 1024.0 / 1024.0 << " Mib cost.\n";
    cerr << (edclock - stclock) * 1.0 / CLOCKS_PER_SEC << " Sec cost.\n";
    return 0;
}
posted @ 2024-03-11 08:47  Call_me_Eric  阅读(33)  评论(0)    收藏  举报
Live2D