Educational Codeforces Round 187(CF2203)
A. Towers of Boxes
所有盒子都是一样的,我们可以算出一个盒子最多可以承受几个盒子,设为\(c\),那么一摞最多有\(c+1\)个,那么答案就是\(\lceil \frac{n}{c+1} \rceil\)。
点击查看代码
//凝视深渊的人,深渊也在凝视你。
#include<bits/stdc++.h>
using namespace std;
int n,m,d;
void qy(){
cin >> n >> m >> d;
int c = d/m+1;
cout << (n+c-1)/c << '\n';
}
signed main(){
int _;cin >> _;
while(_--) qy();
return 0;
}
B - Beautiful Numbers
我们设\(y = f(x)\),那么题目要求达到的条件就是\(f(y) = y\),也就是\(y\)是一位数,就是\(f(x)\)是一位数。
把每一位拆出来,那么除了第一位只可以让\(f(x)\)减少\(a_1-1\),其他的位都可以让\(f(x)\)减少\(a_i\),我们记某一位的贡献为它可以让\(f(x)\)减少的数量。
那么我们贡献从大到小选每一位,知道\(f(x)\)是一位数,这时选了多少位就是最优的了,那么答案就是几。
点击查看代码
//凝视深渊的人,深渊也在凝视你。
#include<bits/stdc++.h>
using namespace std;
string c;
int a[25];
bool cmp(int x,int y){
return x > y;
}
void qy(){
cin >> c;
int n = c.length();
int ans = 0;
for(int i = 1;i <= n;++ i)
ans += c[i-1]-'0',a[i] = c[i-1]-'0';
a[1]--;
sort(a+1,a+1+n,cmp);
int o = 1;
while(ans > 9){
ans -= a[o++];
}
cout << o-1 << '\n';
}
signed main(){
int _;cin >> _;
while(_--) qy();
return 0;
}
C - Test Generator
本题所有的“位”指的都是二进制位。
可以发现\(a_i\)&\(m=a_i\)这个条件说的就是\(a_i\)只能是在\(m\)为\(1\)的位中选一些加在一起,那么我们把所有\(m\)为\(1\)的哪些位上的数记为\(v_1、v_2、v_3 …… v_{vcnt}\),也就是说我们只能用这些数去凑\(S\)。
解释一下$v$数组
比如说$m=149=(10010101)_2$,那么$v$数组就是$1、4、16、128$。
那么我们如果考虑\(S\)的每一位最少用几个\(v_i\)凑出来,那么肯定是用比它位要低且位最高的那个最合适,这样我们就可以十分轻易地算出在最优的情况下每一个\(v_i\)要用多少次,记为\(gs_i\)。
接下来呢?接下来我们考虑二分答案,二分一个数组长度,考虑判断这个数组长度能不能把所有的\(gs_i\)个\(v_i\)都放进去。(要注意这里某一个第\(x\)位不是只能放\(2^x\),也可以放两个\(2^{x-1}\),也就是两个第\(x-1\)位)
那么这样,我们\(check\)的时候从高位到低位扫一遍,如果某一位的个数大于了数组长度,那么就放不下了,我们就把放不下的那些移到更低的一位,那么这样就保证了每一位的个数都小于数组长度,最终判断第\(0\)位的个数是否小于要求的数组长度即可。(看代码理解一下吧)
点击查看代码
//凝视深渊的人,深渊也在凝视你。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int s,m;
int v[65],vs[65];
int gs[65];
int vcnt,vscnt;
int bas[61];
int get_abcd(int x,int y){
if(x > y) swap(x,y);
return bas[y-x];
}
bool check(int x){
int p = gs[vcnt],q = gs[vcnt-1];
for(int i = vcnt;i >= 1;i--){
if(p <= x){
p = gs[i-1];
if(i != 1) q = gs[i-2];
continue;
}
int c = p-x;
q += c*get_abcd(v[i],v[i-1]);
p = q;
if(i != 1) q = gs[i-2];
}
if(p > x) return 0;
return 1;
}
void xm(){
memset(gs,0,sizeof(gs));
vcnt = vscnt = -1;
cin >> s >> m;
int a = 0;
while(m){
if(m&1) v[++vcnt] = a;
m >>= 1;
a++;
}
a = 0;
while(s){
if(s&1) vs[++vscnt] = a;
s >>= 1;
a++;
}
if(v[0] > vs[0]){
cout << "-1\n";
return;
}
for(int i = 0;i <= vscnt;++ i){
int x = upper_bound(v,v+1+vcnt,vs[i])-v-1;
gs[x] += get_abcd(vs[i],v[x]);
}
int l = 1,r = 0;
for(int i = 0;i <= vcnt;++ i)
r = max(r,gs[i]);
while(l < r){
int mid = (l+r)/2;
if(check(mid)) r = mid;
else l = mid+1;
}
cout << r << '\n';
}
signed main(){
bas[0] = 1;
for(int i = 1;i <= 60;++ i)
bas[i] = bas[i-1]*2;
int _;cin >> _;
while(_--) xm();
return 0;
}
D - Divisibility Game
我们可以很轻易地算出来\(b\)中的每一个数\(Alice\)和\(Bob\)分别是否能选,具体来说,枚举\(a\)中每一个数,枚举它所有在范围内的倍数\(j\),让\(vs_j\)加一,那么\(vs_j\)代表的就是\(j\)有多少个因数在\(a\)中。
那么\(Alice\)能选的就是\(vs_{b_i} != 0\)的那些\(b_i\),\(Bob\)能选的就是\(vs_{b_i} != n\)的那些\(b_i\)。(想一下为什么)
那么我们记\(gsa\)为\(Alice\)能选的数的个数,\(gsb\)为\(Bob\)能选的数的个数,\(gsab = gsa+gsb-m\)为两个人都能选的数的个数。
那么一开始,两个人肯定都会去选\(gsab\)那些数,如果\(gsab\)是\(2\)的倍数,那么这些数被选完后刚好又轮到\(Alice\)开始,否则相当于剩下一个给\(Alice\)选的数,那么\(gsa\)加一。
接下来,如果\(gsa > gsb\),那么\(Alice\)会赢,否则\(Bob\)会赢。(这里要仔细考虑一下等于的情况,因为\(Alice\)先取,所以\(Alice\)先没有,他就输了)
点击查看代码
//凝视深渊的人,深渊也在凝视你。
#include<bits/stdc++.h>
using namespace std;
int read(){
int x = 0,y = 1;
char ch = getchar();
while(ch > '9'||ch < '0'){
if(ch == '-') y = -1;
ch = getchar();
}
while(ch >= '0'&&ch <= '9'){
x = x*10+ch-'0';
ch = getchar();
}
return x*y;
}
void print(int x){
if(x < 0) x = -x,putchar('-');
char ch = x%10+'0';
if(x > 9) print(x/10);
putchar(ch);
}
int n,m;
int a[1000005];
int b[1000005];
int vs[2000005];
void xm(){
int gsa,gsb,gsab;
gsa = gsb = gsab = 0;
n = read();m = read();
for(int i = 1;i <= n;++ i)
a[i] = read();
for(int i = 1;i <= m;++ i)
b[i] = read();
int mx = n+m;
sort(a+1,a+1+n);
n = unique(a+1,a+1+n)-a-1;
sort(b+1,b+1+m);
for(int i = 1;i <= n;++ i){
int x = a[i];
for(int j = x;j <= mx;j += x)
vs[j]++;
}
for(int i = 1;i <= m;++ i)
gsa += (vs[b[i]] != 0);
for(int i = 1;i <= m;++ i)
gsb += (vs[b[i]] != n);
gsab = gsa+gsb-m;
gsa -= gsab;
gsb -= gsab;
gsa += (gsab&1);
if(gsa > gsb) cout << "Alice";
else cout << "Bob";
putchar('\n');
for(int i = 1;i <= n;++ i){
int x = a[i];
for(int j = x;j <= mx;j += x)
vs[j]--;
}
}
signed main(){
int _;
cin >> _;
while(_--) xm();
return 0;
}

浙公网安备 33010602011771号