23暑假友谊赛No.2
A-雨
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve() {
vector<int> a(4);
int x;
for( auto &i : a )
cin >> i;
cin >> x;
for( auto i : a)
cout << max( x - i , 0ll ) << " ";
return;
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t = 1 ;
while (t--)
solve();
return 0;
}
B-吻
化简就是\(n^2\)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
void solve() {
int n;
cin >> n;
n %= mod;
n = n * n % mod;
cout << n;
return;
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t = 1 ;
// cin >> t;
while (t--)
solve();
return 0;
}
C-失
把每个字符串按照与答案串不同的字符数量排序即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
typedef pair<int, string> pis;
int operator ^ ( const string & a , const string & b ){
if( a.size() != b.size() ) return 0;
int cnt = 0;
for( int i = 0 ; i < b.size() ; i ++ )
cnt += (a[i] == b[i]);
return cnt;
}
void solve() {
string s;
int n;
cin >> s >> n;
vector<pis> cnt(n);
for( auto &[k,v] : cnt )
cin >> v , k = s ^ v;
sort( cnt.begin(), cnt.end() , [](const pis &x , const pis &y ){
if( x.first != y.first ) return x.first > y.first;
return x.second < y.second;
}) ;
for( int i = 0 ; cnt[i].first == cnt[0].first && i < n ; i ++ )
cout << cnt[i].second << "\n";
return;
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t = 1 ;
// cin >> t;
while (t--)
solve();
return 0;
}
D-吹
可知如果使得绝对值最大,这每个数的取值只有\(1,B_i\)两种。
然后可以跑一个dp 就好了
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int n;
cin >> n;
vector<int> a(n+1);
for( int i = 1 ; i <= n ; i ++ ) cin >> a[i];
vector<array<int,2>> f(n+1);
for( int i = 2 ; i <= n ; i ++ ){
f[i][1] = max( f[i-1][0] + abs( a[i] - 1 ) , f[i-1][1] + abs( a[i] - a[i-1] ) );
f[i][0] = max( f[i-1][0] , f[i-1][1] + abs( a[i-1] - 1 ) );
}
cout << max( f[n][0] , f[n][1] );
return 0;
}
E-唤
一个很经典的贪心,首先4,5,6都是只能单独放的,产生的缝隙可以用来放1,2
。
- 放一个 6,没有缝隙
- 放一个 5,还可以放11个1
- 放一个 4,还可以放5个2
- 一个盒子最多可以放 4 个3
- 放 4 个 3,没有缝隙
- 放 3 个 3,还可以放 1 个 2、5 个 1
- 放 2 个 3,还可以放 3 个 2、6 个 1
- 放 1 个 3,还可以放 5 个 2、7 个 1
- 一个盒子最多可以放 9 个 2,每少放 1 个 2 就可以多放 4 个 1
- 一个盒子最多放 36 个 1
首先尽可能的放 3,4,5,6,并统计缝隙的数量,然后在放 2,2 放的时候有限放缝隙,如果放不下在占用新的盒子,1 同理
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve() {
int s;
cin >> s;
vector<int> k(7), t(7);
for (int i = 1; i <= 6; i++) cin >> k[i];
s -= k[6];
if (s < 0) {
cout << "No\n";
return;
}
s -= k[5], t[1] += 11 * k[5];
if (s < 0) {
cout << "No\n";
return;
}
s -= k[4], t[2] += 5 * k[4];
if (s < 0) {
cout << "No\n";
return;
}
s -= k[3] / 4, k[3] %= 4;
if (k[3] > 0) {
s-- , k[3] = 4 - k[3];
if (k[3] == 1) t[2] += 1, t[1] += 5;
else if (k[3] == 2) t[2] += 3, t[1] += 6;
else t[2] += 5, t[1] += 7;
}
if (s < 0) {
cout << "No\n";
return;
}
if (t[2] >= k[2]) t[2] -= k[2], k[2] = 0, t[1] += 4 * t[2];
else k[2] -= t[2];
s -= k[2] / 9 , k[2] %= 9;
if( k[2] > 0){
s -- , k[2] = 9 - k[2];
t[1] += 4*k[2];
}
if (s < 0) {
cout << "No\n";
return;
}
if( t[1] >= k[1] ) k[1] = 0;
else k[1] -= t[1];
s -= ( k[1] + 35 ) / 36;
if (s < 0) {
cout << "No\n";
return;
}
cout << "Yes\n";
return;
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}
F-冰
首先题目的字符串可以转化成二进制串,再进一步转换成十进制数\([0,65535]\),题目的限制就转化成相邻数\(x\&y=0\)
\(f[i][j]\)表示前\(i\)个数,且最后一个数是\(j\)的方案数,对于数字\(a_i\)有三种情况
- 不选\(a_i\),则\(f[i][j] =f[i-1][j]\)
- 只选\(a_i\),则\(f[i][a_i]=1\)
- 选\(a_i\)也选前面的数,则\(f[i][a_i]=\sum f[i][j],j\in\{0\le j\le 65535\and a_i\&j=0\}\)
这样我们可以用滚动数组优化掉一层,在枚举前一个数选什么即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int n , m;
cin >> n >> m;
vector<int> s(n);
for( int i = 0 ; i < n ; i ++ ){
string str;
cin >> str;
for( int j = 0 ; j < m ; j ++ )
if( str[j] == 'o' ) s[i] = (s[i] << 1) | 1;
else s[i] = s[i] << 1;
}
m = ( 1 << m ) - 1 ;
vector<int> f( m+1 );
for( auto i : s ){
for( int j = 0 ; j <= m ; j ++ )
if( (j & i) == 0 ) (f[i] += f[j]) %= mod;
f[i] = (f[i]+1) % mod;
}
int sum = 0;
for( int i = 0 ; i <= m ; i ++ )
sum = (sum + f[i]) % mod;
cout << sum << "\n";
return 0;
}
上述的代码复杂度\(O(n2^m)\),无法通过。
注意到题目保证了\(n2^\frac{m}{2}<5.12\times10^7\)
则考虑是否可以用\(\sqrt{2^m}\)的枚举
首先我们把16位二进制数拆分成两半,高 8 位和低 8 位,\(f[i][x][y]\)前\(i\)个且最后一个数高位是\(x\),低位是与\(y\)相与为0 的数的方案数
那么此时对于一个数高位是\(x\),低位是\(y\),贡献就是\(ans=1+\sum f[i-1][x’][y],x’\in\{0\le x’\le255\and x’\&x=0\}\)
这样还要考虑更新\(f[i][x][y’] += ans ,y’\in\{0\le y’\le255\and y’\&y=0\}\)
这样枚举其实就是把二进制数分段分段枚举了,能这么做的理由是\(\&\)操作本身不牵扯到位与为之间的操作只受到相同位的影响。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
const int M = 256;
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int n, m, res = 0;
cin >> n >> m;
string s;
vector f(M, vector<int>(M, 0));
for (int x, y, ans; n; n--) {
cin >> s, x = 0 , ans = 1;
for (auto i: s)
if (i == 'o') x = (x << 1) | 1;
else x = x << 1;
y = x % M, x /= M;
for (int i = 0; i < M; i++)
if ((x & i) == 0) ans = (ans + f[i][y]) % mod;
res = (res + ans) % mod;
for (int i = 0; i < M; i++)
if ((i & y) == 0) f[x][i] = (f[x][i] + ans) % mod;
}
cout << res << "\n";
return 0;
}