CF1599
CF1599
Bubble Cup 14 - Finals Online Mirror (Unrated, ICPC Rules, Teams Preferred, Div. 1)
CF1599A
题意
给你一个长度为 \(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
题意
你和你的对手一起玩一个游戏,该游戏共有 \(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
题意
给定长度为 \(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\),那么有
不难求出首项 \(a\)。
然后要判定 \(k\) 次幂仍然是对的。
右边的式子是好求的。
左边的式子不好求,考虑二项式定理:
然后 \(\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;
}

浙公网安备 33010602011771号