Codeforces Round 964 (Div.4)题解

题目链接

差一道题就ak了,打代码的速度还是慢了点

F时间不够了,于是随便糊了个时间复杂度不对的算法,结果算法对了,少了个预处理然后就TLE了,赛时没有发现

A.A+B Again?

1
2
3
4
5
6
7
8
9
10
11
#include<iostream>
using namespace std;
int t , n;
signed main(){
cin >> t;
while( t -- ){
cin >> n;
cout << (n/10)+(n%10) << endl;
}
return 0;
}

B.Card Game

直接穷举所有可能性即可

思路不是很难,就看如何实现了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<iostream>
#define int long long
using namespace std;

int t , a[5];

signed main(){
cin >> t;
while( t -- ){
for(int i = 1;i <= 4;i ++) cin >> a[i];
int l , r , ans = 0;
for(int i = 1;i <= 2;i ++){
int ii = (i==1)?2:1;
for(int j = 3;j <= 4;j ++){
int jj = (j==3)?4:3;
l = 0 , r = 0;
if( a[i] > a[j] ) l ++;
if( a[i] < a[j] ) r ++;

if( a[ii] > a[jj] ) l ++;
if( a[ii] < a[jj] ) r ++;

if( l > r ) ans ++;
//cout << a[i] << " " << a[ii] << " " << a[j] << " " << a[jj] << endl;
}
}
cout << ans << endl;
}
return 0;
}

C.Showering

典型贪心(弱化版)

数据范围可以 \(O(nlogn)\),无脑sort就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;

const int N = 2e5;
int t , n , s , m;
struct TIME{
int l , r;
}a[N+10];

bool cmp( TIME x , TIME y ){
return x.l < y.l;
}

signed main(){
cin >> t;
while( t -- ){
cin >> n >> s >> m;
for(int i = 1;i <= n;i ++){
cin >> a[i].l >> a[i].r;
}
sort( a + 1 , a + n + 1 , cmp );
bool flag = 0;
a[0].r = 0 , a[n+1].l = m;
for(int i = 1;i <= n+1;i ++){
if( a[i].l - a[i-1].r >= s ){
flag = 1;
break;
}
}
if( flag ) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}

D.Slavic's Exam

这里的匹配不需要连续,所以只要有?就直接替换就可以了,多余的?需要替换成任意小写字母

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<iostream>
#include<string>
#define int long long
using namespace std;

int T;
string s , t;

signed main(){
cin >> T;
while( T -- ){
cin >> s >> t;
int t_top = 0;
//cout << s.length() << " " << t.length() << endl;
for(int i = 0;i < s.length();i ++){
if( t_top == t.length() ){
if( s[i] == '?' ) s[i] = 'a';
continue;
}
if( s[i] == '?' || s[i] == t[t_top] ){
s[i] = t[t_top];
t_top ++;
}
}
if( t_top != t.length() ) cout << "NO" << endl;
else{
cout << "YES" << endl;
cout << s << endl;
}
}
return 0;
}

E.Triple Operations

这道题开始上难度了

先说结论,\(ans=log_3(min(a_i))+\sum log_3(a_i)\)

容易观察到,我们只需要将其中一个数变为0,后续将数字除以3(减小)的时候不会造成其他数字乘以3(增大),我们只需要将最小的数变为0就可以,但是同时也会有另外一个数字增大,这时造成的代价即为\(log_3(min(a_i))\)

现在只需要计算 \(log_3(min(a_i))+\sum log_3(a_i)\) ,即\(log_3l+\sum_l^r log_3(a_i)\)

我们观察到从 \(l\)\(r\) 是单调的,所以利用指数即可在 \(O(logn)\) 求解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include<iostream>
#include<string>
#define int long long
using namespace std;

int T;
int l , r;

int log3( int x ){
int ans = 0;
while( x ){
x /= 3;
ans ++;
}
return ans;
}

int poww( int x ){
int ans = 1;
while( x -- ){
ans *= 3;
}
return ans;
}

signed main(){/*
for(int i = 1;i <= 100;i ++){
cout << i << " | " << log3(i) << endl;
}
return 0;*/
cin >> T;
while( T -- ){
cin >> l >> r;
/*
int ans = log3(l);
for(int i = l;i <= r;i ++){
ans += log3(i);
}*/
int ans = log3(l)+log3(r) , log_i , jumper;
for(int i = l;i <= r;i ++){
log_i = log3(i);
jumper = poww( log_i );
//cout << "jumper: " << jumper << " |ans: " << ans << endl;
if( jumper < r ) ans += (jumper-i)*log_i , i = jumper-1;
else ans += (r-i)*log_i , i = r;
}
cout << ans << endl;

}
return 0;
}

F.Expected Median

假设 \(1\)\(x\) 个,\(0\)\(y\) 个,那么 $ans=(C_xi+C_y{k-i}) $,即从 \(x\) 中选 \(i\) 个,从 \(y\) 中选 \(k-i\) 个的所有可能,其中 \(i\) 需要满足 从 \(x\) 中取出的元素多余从 \(y\) 中取出(即 \(1\)\(0\) 多,这样的中位数才能是 \(1\)

计算组合数需要用阶乘,记得预处理(悲

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include<iostream>
#include<string>
#define int long long
using namespace std;

const int N = 2e5 , p = 1e9+7;
int T , n , k;
int a[N+10];
int num_0 , num_1;
int jc[N+10];

void init(){
jc[0] = 1;
for(int i = 1;i <= N;i ++){
jc[i] = jc[i-1]*i;
jc[i] %= p;
}
return ;
}

int qpow(long long a, int b) {
int ans = 1;
a = (a % p + p) % p;
for (; b; b >>= 1) {
if (b & 1) ans = (a * ans) % p;
a = (a * a) % p;
}
return ans;
}

int inv( int x ){
return qpow( x , p-2 );
}

int C( int nn , int mm ){
int ans = 1;
ans *= jc[nn];
ans %= p;
ans *= inv(jc[mm]);
ans %= p;
ans *= inv(jc[nn-mm]);
ans %= p;
return ans;
}

signed main(){
init();
cin >> T;
while( T -- ){
cin >> n >> k;
num_0 = num_1 = 0;
for(int i = 1;i <= n;i ++){
cin >> a[i];
if( a[i] ) num_1 ++ ; else num_0 ++;
}
int ans = 0;
for(int i = min(num_1,k);i>k/2 and (k-i)<=num_0;i --){
//cout << num_0 << " " << k-i << " " << num_1 << " " << i << endl;
ans += C( num_0 , k-i ) * C( num_1 , i );
ans %= p;
}
cout << ans << endl;
}
return 0;
}

G1.Ruler (easy version)

简单的二分法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<iostream>
#include<string>
#define int long long
using namespace std;

const int N = 2e5 , p = 1e9+7;
int T , t;

int ef( int l , int r ){
if( l == r ) return l;
int mid = (l+r)>>1;
cout << "? " << mid << " " << mid << endl;
cout << flush;
int t;
cin >> t;
//int redder = mid + ( mid>=100?1:0);
//t = redder*redder;
if( t == (mid+1)*(mid+1) ) return ef( l , mid );
else return ef( mid+1 , r );
}

signed main(){
cin >> T;
while( T -- ){
int ans = ef( 2 , 999 );
cout << "! " << ans << endl;
cout << flush;
}
return 0;
}

G2.Ruler (hard version)

三分法,写法有很多,七次询问可以确定一个数即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<iostream>
#include<string>
#define int long long
using namespace std;

const int N = 2e5 , p = 1e9+7;
int T , t;

int ef( int l , int r ){
if( l == r ) return l;
int mid_l = l+(r-l)/3 , mid_r = l+(r-l)/3*2;
cout << "? " << mid_l << " " << mid_r << endl;
cout << flush;
int t;
cin >> t;/*
int lll = mid_l + ( mid_l>=700?1:0);
int rrr = mid_r + ( mid_r>=700?1:0);
t = lll*rrr;*/
if( t == (mid_l+1)*(mid_r+1) ) return ef( l , mid_l );
else if( t == (mid_l)*(mid_r+1) ) return ef( mid_l+1 , mid_r );
else return ef( mid_r+1 , r );
}

signed main(){
cin >> T;
while( T -- ){
int ans = ef( 2 , 999 );
cout << "! " << ans << endl;
cout << flush;
}
return 0;
}