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

  1. 放一个 6,没有缝隙
  2. 放一个 5,还可以放11个1
  3. 放一个 4,还可以放5个2
  4. 一个盒子最多可以放 4 个3
    1. 放 4 个 3,没有缝隙
    2. 放 3 个 3,还可以放 1 个 2、5 个 1
    3. 放 2 个 3,还可以放 3 个 2、6 个 1
    4. 放 1 个 3,还可以放 5 个 2、7 个 1
  5. 一个盒子最多可以放 9 个 2,每少放 1 个 2 就可以多放 4 个 1
  6. 一个盒子最多放 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\)有三种情况

  1. 不选\(a_i\),则\(f[i][j] =f[i-1][j]\)
  2. 只选\(a_i\),则\(f[i][a_i]=1\)
  3. \(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;
}
posted @ 2023-07-26 19:49  PHarr  阅读(6)  评论(0编辑  收藏  举报