One Bamboo Contest Round #11(Clone from 2022 ICPC Manila)
马尼拉区域赛题目出得还是不错的,只是感觉大多数参赛队伍的水平不太行,我们这样的队伍居然能苟到铜牌
A. An Easy Calculus Problem
签到
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int a = -2 , b = 1 , c = -14 , d = 17;
int f( int x ){
if( x <= - 3 ) return - ( x + 4 ) * ( x + 4 ) + 8;
if( x <= 2 ) return a * x +b;
return x * x * x + c * x + d;
}
int32_t main(){
int x;
cin >> x;
cout << f(x) << "\n";
return 0;
}
J. Junior Steiner Three
这题就是要用尽可能少的#把起始的三个#连在一起。如果是两个点的话很好做,就是曼哈顿距离就好。而三个点就是要找一个点距离三个#的曼哈顿距离之和最短即可。然后按照曼哈顿距离的方式连起来,所消耗的#就是曼哈顿距离减一
#include <bits/stdc++.h>
using namespace std;
int32_t main(){
int n , m;
cin >> n >> m;
vector<vector<int>> v( n , vector<int>(m) );
vector<pair<int,int>> node;
for( int i = 0 ; i < n ; i ++ ){
string s; cin >> s;
for( int j = 0 ; j < m ; j ++ )
if( s[j] == '#' ) v[i][j] = 1 , node.push_back(make_pair(i,j));
}
int res = INT_MAX , sx , sy;
auto dis = []( int a , int b , int x , int y){
return abs( a - x ) + abs( b - y );
};
for( int i = 0 , t ; i < n ; i ++ )
for( int j = 0 ; j < m ; j ++ ){
t = 1;
for( auto [x,y] : node ) t += dis( i , j , x , y ) - 1;
if( t < res ) res = t , sx = i , sy = j;
}
for( auto [x,y] : node ){
for( int i = min(sx,x) ; i <= max(sx,x) ; i ++ ) v[i][sy] = 1;
for( int i = min(sy,y) ; i <= max(sy,y) ; i ++ ) v[x][i] = 1;
}
for( auto i : v ){
for( auto j : i ) cout << ".#"[j];
cout << "\n";
}
return 0;
}
K. Kapitan Amazing(补队友题)
其实很好做,就是把字母集用01串表示,然后做异或就好。
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false) , cin.tie(nullptr);
string A = "QWERTYUIOP" , B = "ASDFGHJKL" , C = "ZXCVBNM";
string a , b , c;
cin >> a >> b >> c;
int tmp = 0 , n , cur;
for( int i = 0 ; i < a.size() ; i ++ )
if( a[i] != A[i] ) tmp += 1 << (A[i] - 'A');
for( int i = 0 ; i < b.size() ; i ++ )
if( b[i] != B[i] ) tmp += 1 << (B[i] - 'A');
for( int i = 0 ; i < c.size() ; i ++ )
if( c[i] != C[i] ) tmp += 1 << (C[i] - 'A');
cin >> n;
for( string s ; n ; n -- ){
cin >> s;
cur = 0;
for( auto i : s )
cur |= 1 << (i - 'A');
cout << ( (cur^tmp) == 0 ? "POSSIBLE\n" : "IMPOSSIBLE\n");
}
}
C. Conform Conforme(补队友题)
用unorder_map
可以做到\(O(n)\)的替换,然后做\(k\)次就行,但是实际上当\(k\)比较大时,操作不了\(k\)次序列就不会变了。因为第\(i\)次操作后序列中的元素就会大于等于\(2^{i-1}\),所以至多操作\(\log_2(n)\)次
#include <bits/stdc++.h>
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;
}
int main(){
int n = read() , k = read();
vector<int> a(n);
for( auto & i : a ) i = read();
for( int t = min( k , (int)log2(n) + 1 ) ; t ; t -- ){
unordered_map<int,int> mp;
for( auto i : a ) mp[i] ++;
for( auto &i : a ) i = mp[i];
}
for( auto &i : a )
printf("%d " , i );
return 0;
}
F. Factions vs The Hegemon(补队友题)
这题的意思是有霸权删除最小的,没有霸权删除最大的,最值不唯一删除编号最小的,并且删除后把元素的值分给两侧。然后用set维护一下集合就好,每次从set中找到最大的,然后判断是否有霸权,set内部是一个(wealth,index)
的`pair。至于相邻的情况维护一个前驱后继的数组即可,删除时像双链表删除一样维护一下即可。
#include <bits/stdc++.h>
#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;
}
struct node{
int wealth , index;
node( int wealth = 0 , int index = 0 ) : wealth(wealth) , index(index) {};
bool operator < ( const node & b ) const{
if( wealth != b.wealth ) return wealth < b.wealth;
return index < b.index;
}
};
int32_t main(){
int n = read() , sum = 0;
std::vector<int> w(n+5) , prev(n+5) , next(n+5);
for( int i = 1 ; i <= n ; i ++ )
w[i] = read() , sum += w[i] , prev[i] = i-1 , next[i] = i+1;
prev[1] = next[n] = -1;
std::set<node> st;
for( int i = 1 ; i <= n ; i ++ ) st.insert( node( w[i] , i ) );
auto del = [&]( int i ){
int a = prev[i] , b = next[i] , wi = w[i] , wa , wb;
printf("%lld %lld\n" , i , wi );
st.erase(node(wi,i)) , sum -= wi , wi /= 2 , w[i] = -1 ;
if( a != -1 ) sum += wi , wa = w[a] , next[a] = b , st.erase( node(wa,a) ) , w[a] = wa = wa + wi , st.insert(node(wa,a));
if( b != -1 ) sum += wi , wb = w[b] , prev[b] = a , st.erase( node(wb,b) ) , w[b] = wb = wb + wi , st.insert(node(wb,b));
return;
};
for( int t = n , id ; t ; t -- ){
auto it = *st.rbegin();
if( it.wealth > sum - it.wealth ) // 霸权
id = st.begin()->index;
else
id = st.lower_bound( node(it.wealth , -1 ) )->index;
del(id);
}
return 0;
}
G. Gallivanting Merchant(补题)
这道题首先知道\(S\)的取值范围是\([0,k)\)。我们用用一个数组来表示\(S\)每一个取值对应的答案。然后用差分来实现区间修改。
如果\(R-L+1>k\)则\([0,k-1]\)区间加1。
反之令$l=L\mod k , r = R \mod k \(,则\)[l,r]\(区间加1,注意如果\)l>r\(则要\)[0,r],[l,k-1]$区间加1
然后k的范围虽然很大,但\(l,r\)取值没有那么多离散化一下就行,这里我直接用map实现。
#include <bits/stdc++.h>
#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;
}
int32_t main(){
int n = read() , k = read();
vector< pair<int,int> > a(n);
for( auto &[l,r] : a ) l = read() , r = read();
map<int,int> diff;
for( auto [ l , r ] : a) {
if( r - l + 1 >= k ) diff[0] ++ , diff[k] --;
else{
int L = l % k , R = r % k;
if( L > R ) diff[0] ++ , diff[R+1]-- , diff[L] ++ , diff[k] -- ;
else diff[L] ++ , diff[R+1] --;
}
}
for( auto it = diff.begin() ; next(it) != diff.end() ; it = next(it) ){
next(it)->second += it->second;
}
int res = 0;
for( auto [k,v] : diff ) res = max( res , v );
cout << res << "\n";
return 0;
}
I. Item Crafting(补题)
可以把最终产品转化成原材料的集合,然后因为最终产品很少,所用可以暴力去枚举出所有可能出现的集合然后暴力判断就好。
因为每一个产品的组成材料的ID一定比产品本身打,所以可以通过倒序的方式保证每一个产品只用操作一次就可以变成全部由原材料构成的。注意该过程中材料的数量会超出long long
的范围,但其实一旦用料超过p
之后我们就不用考虑他到底超了多少,把他们都表示位p+1
即可
#include <bits/stdc++.h>
#define int __int128
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;
}
int res = 0 , n , m ;
map<int,int> p;
set<int> material;
vector< map<int,int> > craft;
void dfs( int x , int val , map<int,int> tmp ){
bool flag = true;
for( auto i : material)
if( p[i] < tmp[i] ){
flag = false;
break;
}
if(flag) res = max( res , val ) ;
if( x == n + 1 ) return;
dfs( x + 1 , val , tmp );
for( auto [k,v] : craft[x]) tmp[k] += v;
dfs( x+1 , val+1 , tmp );
return ;
}
int32_t main(){
n = read() , m = read();
craft.resize(m+1);
for( int i = 1 , c ; i <= m ; i ++ ){
c = read();
if( c == 0 ) material.insert(i) , p[i] = read();
else{
for( int j = 1 , x ; j <= c ; j ++ )
x = read() , craft[i][x] ++;
}
}
for( int i = m ; i >= 1 ; i -- ){
if( material.count(i) ) continue;
vector<int> del;
for( auto &[ k , v ] : craft[i] ){
if( material.count(k) || v == 0 ) continue;
del.push_back(k);
for( auto [ kk , vv ] : craft[k] ){
craft[i][kk] += vv * v;
if( craft[i][kk] > p[kk] ) craft[i][kk] = p[kk] + 1;
}
}
for( auto k : del ) craft[i].erase(k);
}
dfs( 1 , 0 , map<int,int>() );
cout << (long long)res << "\n";
return 0;
}