CF 790 Div.4完整题解
A. Lucky?
给n 个长度6 的数,问前三位和后三位中0 的数量是否相同
#include <bits/stdc++.h>
using namespace std;
string s;
int main(){
int t = read();
while( t -- ){
cin >> s;
int a = 0 , b = 0;
for( int i = 0 ; i < 3 ; i ++ )
a += s[i] - '0';
for( int i = 3 ; i < 6 ; i ++ )
b += s[i] - '0';
if( a == b )
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
B. Equal Candies
有 n 个盒子每个盒子里面有\(a_i\)个糖果,可以吃掉任何一个盒子的任意数量个糖果,问最少吃掉多少糖果能使所有盒子糖果数量相同
找到糖果最少的盒子,其他盒子都变成这个数量就行
#include <bits/stdc++.h>
#define ll long long
using namespace std;
string s;
int lcm( int x , int y ){
return x * y / __gcd( x , y ) ;
}
int read(){
int x = 0 , f = 1 , ch = getchar();
while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
return x*f;
}
const int N = 55;
int a[N] , n , m ;
ll sum;
void solve(){
n = read() , m = 1e9 , sum = 0;
for( int i = 1 ; i <= n ; i ++ )
a[i] = read() , m = min( a[i] , m );
for( int i = 1 ; i <= n ; i ++ )
sum += a[i] - m;
cout << sum << endl;
}
int main(){
int t = read();
while( t -- )
solve();
return 0;
}
C. Most Similar Words
给 n 个长度是 m 的字符串,从中选出两个两个字符串的差最小是多少
因为数据很小直接枚举一下就行,\(O(n^2m)\)
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int read(){
int x = 0 , f = 1 , ch = getchar();
while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
return x*f;
}
const int N = 55;
int n , m , sum , res;
string s[N];
void solve(){
n = read() , m = read();
for( int i = 1 ; i <= n ; i ++ )
cin >> s[i];
res = 1e9;
for( int i = 1 ; i < n ; i ++ )
for( int j = i + 1 ; j <= n ; j ++ )
{
sum = 0;
for( int k = 0 ; k < m ; k ++ )
sum += abs( s[i][k] - s[j][k] );
res = min( res , sum );
}
cout << res << endl;
}
int main(){
int t = read();
while( t -- )
solve();
return 0;
}
D. X-Sum
\(n^3\)解法
这个是显然的一种做法,就是直接枚举出每一个点,然后计算出和就好
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int lcm( int x , int y ){
return x * y / __gcd( x , y ) ;
}
int read(){
int x = 0 , f = 1 , ch = getchar();
while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
return x*f;
}
const int N = 500;
int n , m , sum , res;
int st[N][N];
void solve(){
n = read() , m = read();
for( int i = 1 ; i <= n ; i ++ )
for( int j = 1 ; j <= m ; j ++ )
st[i][j] = read();
res = 0;
for( int i = 1 ; i <= n ; i ++ )
for( int j = 1 ; j <= m ; j ++ )
{
sum = st[i][j];
for( int x = i-1 , y = j-1 ; x >= 1 && y >= 1 ; x -- , y -- )
sum += st[x][y];
for( int x = i-1 , y = j+1 ; x >= 1 && y <= m ; x -- , y ++ )
sum += st[x][y];
for( int x = i+1 , y = j-1 ; x <= n && y >= 1 ; x ++ , y -- )
sum += st[x][y];
for( int x = i+1 , y = j+1 ; x <= n && y <= m ; x ++ , y ++ )
sum += st[x][y];
res = max( res , sum );
}
cout << res <<'\n';
}
int main(){
int t = read();
while( t -- )
solve();
return 0;
}
\(n^2\)做法
可以首先计算出每一条斜线的和,然后再枚举一下中心点把两条斜线加起来即可
那么如何判断点在哪条斜线上呢?
一条左斜的斜线距离\((1,1)\)的欧拉距离相同, 同理一条右斜的斜线距离\((n,n)\)的欧拉距离相同
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int lcm( int x , int y ){
return x * y / __gcd( x , y ) ;
}
int read(){
int x = 0 , f = 1 , ch = getchar();
while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
return x*f;
}
const int N = 500;
int n , m , sum , res;
int st[N][N] , lc[2*N] , rc[2*N];
void solve(){
n = read() , m = read();
memset( lc , 0 , sizeof(lc) ) , memset( rc , 0 , sizeof(rc) );
for( int i = 1 ; i <= n ; i ++ )
for( int j = 1 ; j <= m ; j ++ )
st[i][j] = read();
int l , r ;
for( int i = 1 ; i <= n ; i ++ )
for( int j = 1 ; j <= m ; j ++ )
{
l = i - 1 + j - 1 , r = n - i + j - 1;
lc[l] += st[i][j] , rc[r] += st[i][j];
}
res = 0;
for( int i = 1 ; i <= n ; i ++ )
for( int j = 1 ; j <= m ; j ++ )
{
l = i - 1 + j - 1 , r = n - i + j - 1;
sum = lc[l] + rc[r] - st[i][j];
res = max( res , sum );
}
cout << res << endl;
}
int main(){
int t = read();
while( t -- )
solve();
return 0;
}
E. Eating Queries
有 n 颗糖果,每个糖果有一个甜度\(a_i\),问需要甜度\(x\)至少要吃多少个糖果,每次询问相互独立
首先糖果数要少,就要优先吃甜度高的糖果。
把糖果从大到小排序,然后求一个前缀和,对于每次的询问在前缀和二分查找即可
#include <bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;
int read(){
int x = 0 , f = 1 , ch = getchar();
while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
return x*f;
}
const int N = 2e5+5;
int n , a[N] , m ;
void solve(){
n = read() , m = read();
for( int i = 1 ; i <= n ; i ++ )
a[i] = read();
sort( a + 1 , a+1+n , greater<int>() );
for( int i = 1 ; i <= n ; i ++ )
a[i] += a[i-1];
for( int x , t ; m ; m -- )
{
x = read();
if( x > a[n] )
printf("-1\n");
else
{
t = lower_bound( a+1 , a+1+n , x ) - a;
printf("%lld\n" , t );
}
}
}
int32_t main(){
int t = read();
while( t -- )
solve();
return 0;
}
F. Longest Strike
给定一个序列,找出一个最长的区间,区间中的每个数都至少出现了 k 次
可以在 map 开一个桶来记录,同时因为的 map 内部本身可以排序的,我们扫一边就好了
注意的是,在扫的过程中我们判断当前数是否是大于等于 k 以外还要判断当前数是否和上一个数相邻
#include <bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;
int read(){
int x = 0 , f = 1 , ch = getchar();
while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
return x*f;
}
const int N = 2e5+5;
int n , t , l , r ;
map< int , int > st;
void solve(){
n = read() , t = read();
st.clear();
for( int i = 1 , x ; i <= n ; i ++ )
x = read() , st[x] ++;
int res = -1 , last = -1e9 , lastk = -1e9;
for( auto [k,v] : st ){
if(v >= t ){
if( last == -1e9 || lastk+1 != k ) last = k;
if( k - last > res )
res = k - last , l = last , r = k;
}
else last = -1e9;
lastk = k;
}
if( res == -1 ) printf("-1\n");
else cout << l << ' ' << r << endl;
}
int32_t main(){
int t = read();
while( t -- )
solve();
return 0;
}
G. White-Black Balanced Subtrees
给一个树,树上的每一个点都已一个颜色黑或者白,问有多少个点满足子树中的黑白点数量相同
看似复杂实际上就是直接用 dfs 过程中统计下子树中黑白点的数量就好了
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int read(){
int x = 0 , f = 1 , ch = getchar();
while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
return x*f;
}
const int N = 4005;
int n , cnt , b[N] , w[N];
vector<int> e[N];
string s;
void dfs( int x ){
if( s[x-1] == 'B' ) b[x] ++;
else w[x] ++;
for( auto v : e[x] ){
dfs( v );
b[x] += b[v] , w[x] += w[v];
}
if( b[x] == w[x] ) cnt ++ ;
}
void solve(){
n = read() , cnt = 0;
for( int i = 1 ; i <= n ; i ++ )
e[i].clear() , b[i] = w[i] = 0;
for( int i = 2 , u ; i <= n ; i ++ )
u = read() , e[u].push_back(i);
cin >> s;
dfs( 1 );
cout << cnt << endl;
}
int32_t main(){
int t = read();
while( t -- )
solve();
return 0;
}
H. Maximum Crossings
有两条线段,每个线段有 n 段 给定第一条线段与第二条线段连线的区间,问最多有多少个交点
这题有两个版本,我直接写的困难版本
其实这个题就是一个模板题,就是一个逆序对,只不过需要考虑一下边界
#include <bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;
int read(){
int x = 0 , f = 1 , ch = getchar();
while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
return x*f;
}
#define lowbit(x) ( x & -x )
const int N = 2e5+5;
int n , c[N] , cnt;
inline void update( int x ) // 更新 bit[x] += 1
{
for( int i = x ; i <= n ; i += lowbit( i ) ) c[i] += 1;
}
inline int get( int x ) //求a[1...x]
{
int ans = 0;
for( int i = x ; i ; i -= lowbit( i ) ) ans += c[i];
return ans;
}
void solve(){
n = read() , cnt = 0;
memset( c , 0 , sizeof (c) );
for( int i = 1 , x ; i <= n ; i ++ )
{
x = read();
cnt += i-1 - get(x-1);
update(x);
}
cout << cnt << endl;
}
int32_t main(){
int t = read();
while( t -- )
solve();
return 0;
}