2024 ICPC 成都 ABGIJL题

链接:

2024 ICPC Asia Chengdu Regional Contest (The 3rd Universal Cup. Stage 15: Chengdu)

A:Arrow a Row

大意:

       

思路:

       先判断不能的,长度小于5或者第一个跟最后三个不是箭头的都不能,还有就是没有横线的也不能。

        其他都是能的,现在就看怎么构造,直接先第一个和最后一堆箭头,然后中间的的和最后一堆箭头的前三个,注意顺序,要不箭头就会被覆盖。

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define  vi vector<int>
#define  vii vector<pair<int, int>>
#define ff first 
#define ss second 
// ++   ~!    */+-    <<>>    <>  ==   &^|   &&|| =


void solve()
{
    string s;cin >> s;
    int n = s.size();
    s = '!' + s;

    if (n < 5)
    {
        cout << "No" << endl;
        return;
    }
    bool flag = false;
    for (int i = 1; i <= n; i++){
        if (s[i] == '-'){
            flag = true;
            break;
        }
    }
    int d[] = { 1, n - 2, n - 1, n };
    for (int i = 0; i < 4; i++)
        if (s[d[i]] != '>')flag = false;
    if (!flag)
    {
        cout << "No" << endl;
        return;
    }

    vector<pair<int, int>> v;
    int i;
    for (i = n - 2; i > 1; i--)
        if (s[i] == '>')v.push_back({ 1, i + 2 });
        else break;
    
    for (int j = 2; j < i; j++)
        if (s[j] == '>')v.push_back({ j, i + 3 - j + 1 });

    int num = v.size();
    cout << "Yes " << num << endl;
    for (int i = 0; i < num; i++)
        cout << v[i].ff << ' ' << v[i].ss << endl;
}

signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

    int t = 1;
    cin >> t;
    while (t--) solve();

    return 0;
}
/*   /\_/\
*   (= ._.)
*   / >  \>
*/

 B:Athlete Welcome Ceremony

大意:

思路:

     dp + 三维前缀和

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define  vi vector<int>
#define  vii vector<pair<int, int>>
#define ff first 
#define ss second 
// ++   ~!    */+-    <<>>    <>  ==   &^|   &&|| =

int dp[310][310][310][3]; // ijkz  对前i个字符,使用了j个a字符,k个b字符,第i个字符是 z + 'a'的方案数
int f[310][310][310]; // 有i个a,j个b,k个c的方案数

void solve()
{
    int n, m;
    cin >> n >> m;
    string s;cin >> s;
    s = ' ' + s;
    vector<int> cnt(n + 1);
    for (int i = 1; i <= n; i++)cnt[i] = cnt[i - 1] + (s[i] == '?');

    // 先初始化一下方案数
    if (s[1] == '?')
        dp[1][1][0][0] = dp[1][0][1][1] = dp[1][0][0][2] = 1;
    else
        dp[1][0][0][s[1] - 'a'] = 1;
    

    for (int i = 2; i <= n; i++)
    {
        for (int ca = 0; ca <= cnt[i]; ca++)
        {
            for (int cb = 0; cb + ca <= cnt[i]; cb++)
            {
                
                if (s[i] != '?')
                {
                    int num = dp[i - 1][ca][cb][0] + dp[i - 1][ca][cb][1] + dp[i - 1][ca][cb][2]; //上一层总方案数
                    dp[i][ca][cb][s[i] - 'a'] = (num - dp[i - 1][ca][cb][s[i] - 'a']) % mod; // 去掉上一层一样的,其他结尾字母为0
                    continue;
                }
                if (ca)
                {
                    int num = dp[i - 1][ca - 1][cb][1] + dp[i - 1][ca - 1][cb][2]; 
                    dp[i][ca][cb][0] = num % mod;
                }
                if (cb)
                {
                    int num = dp[i - 1][ca][cb - 1][0] + dp[i - 1][ca][cb - 1][2];
                    dp[i][ca][cb][1] = num % mod;
                }
                if (cnt[i] - ca - cb)
                {
                    int num = dp[i - 1][ca][cb][0] + dp[i - 1][ca][cb][1];
                    dp[i][ca][cb][2] = num % mod;
                }

            }
        }
    }

    // 先获得特定i j k对应的方案数
    for(int i = 0; i <= cnt[n]; i ++) 
        for (int j = 0; i + j <= cnt[n]; j++)
        {
            int num = dp[n][i][j][0] + dp[n][i][j][1] + dp[n][i][j][2];
            f[i][j][cnt[n] - i - j] = num % mod; 
        }
     // 获得i j k有富余的情况对应的方案数 三维前缀和
    for (int i = 0; i <= 300; i++) {
        for (int j = 0; j <= 300; j++) {
            for (int k = 0; k <= 300; k++) {
                if (i > 0) f[i][j][k] += f[i - 1][j][k];
                if (j > 0) f[i][j][k] += f[i][j - 1][k]; 
                if (k > 0) f[i][j][k] += f[i][j][k - 1]; 
                if (i && j)f[i][j][k] += mod - f[i - 1][j - 1][k];
                if (k && j)f[i][j][k] += mod - f[i][j - 1][k - 1];
                if (i && k)f[i][j][k] += mod - f[i - 1][j][k - 1];
                if (i && j && k)f[i][j][k] += f[i - 1][j - 1][k - 1];
                f[i][j][k] %= mod;
            }
        }
    }

    while (m --) 
    {
        int x, y, z; cin >> x >> y >> z;
        cout << f[x][y][z] << '\n';
    }
}

signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    
    int t = 1;
    //cin >> t;
    while (t--) solve();

    return 0;
}
/*   /\_/\
*   (= ._.)
*   / >  \>
*/

 G:Expanding Array

大意:

思路:

        这里我的思考流程是:

        1、先发现两个数操作可以转换成两个数无限操作

        2、再发现对于x的某位,y的对应位,

                x = 1,y = 1

                x = 1,  y = 0

                x = 0,  y = 1

                x = 0,  y = 0

                每个位都对应以上一种情况,进行操作时,这些位属于同一类的会发生相同的变化,那么最后的结果就是这四类的自由组合,放到set 里面去重就行

        下面是官方题解:

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define  vi vector<int>
#define  vii vector<pair<int, int>>
#define ff first 
#define ss second 
// ++   ~!    */+-    <<>>    <>  ==   &^|   &&|| =


void solve()
{
    int n;cin >> n;
    vi a(n + 1);

    for (int i = 1; i <= n; i++)cin >> a[i];
    set<int>S;
    S.insert(0);

    for (int i = 2; i <= n; i++)
    {
        int n11 = 0, n10 = 0, n01 = 0;
        for (int j = 31; j >= 0; j--)
        {
            int n1 = a[i - 1] & (1LL << j);
            int n2 = a[i] & (1LL << j);
            if (n1 && n2)n11 |= n1;
            else if (n1)n10 |= n1;
            else if (n2)n01 |= n2;
        }
        vi v = { n11, n10, n01, n11 + n10, n11 + n01, n10 + n01, n11 + n01 + n10 };
        for (auto it : v)S.insert(it);
    }
    cout << S.size() << endl;

}

signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

    int t = 1;
    //cin >> t;
    while (t--) solve();

    return 0;
}
/*   /\_/\
*   (= ._.)
*   / >  \>
*/

I:Good Partitions

大意:

思路:

为什么求gcd可以用断点i?,因为(a, b, c)  = (a, b - a, c - b),正好为区间长度

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define  vi vector<int>
#define  vii vector<pair<int, int>>
#define ff first 
#define ss second 
// ++   ~!    */+-    <<>>    <>  ==   &^|   &&|| =

int cnt[N];
int n, m;
struct node
{
    int l, r, d;
}tr[N << 2];

int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}

void pushup(int u)
{
    tr[u].d = gcd(tr[u << 1].d, tr[u << 1 | 1].d);
}

void build(int u, int l, int r)
{
    tr[u] = { l, r, 0 };
    if (l != r)
    {
        int mid = l + r >> 1;
        build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    }
}

void modify(int u, int x, int v)
{
    if (tr[u].l == tr[u].r)tr[u].d = v;
    else
    {
        int mid = tr[u].l + tr[u].r >> 1;
        if (x <= mid)modify(u << 1, x, v);
        else modify(u << 1 | 1, x, v);

        pushup(u);
    }
}


void solve()
{
    cin >> n >> m;
    build(1, 1, n);

    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i < n; i++)
    {
        if (a[i] > a[i + 1])modify(1, i, i);
        else modify(1, i, 0);
    }
    int ans = tr[1].d;
    if (ans == 0)cout << n << endl; // 每次都要特判全零
    else cout << cnt[ans] << endl; // 答案就为最大公约数的约数个数

    int p, v;
    while (m--)
    {
        cin >> p >> v;
        a[p] = v;
        // 修改一个点,影响前向差分和后向差分
        if (a[p - 1] > a[p])modify(1, p - 1, p - 1);
        else modify(1, p - 1, 0);
        if (p < n)
        {
            if (a[p] > a[p + 1])modify(1, p, p);
            else modify(1, p, 0);
        }

        int ans = tr[1].d;
        if (ans == 0)cout << n << endl;
        else cout << cnt[ans] << endl;
    }

}

signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

    for (int i = 1; i <= 200001; i++)
        for (int j = 1; j * i <= 200001; j++)
            cnt[i * j] ++;

    int t = 1;
    cin >> t;
    while (t--) solve();

    return 0;
}
/*   /\_/\
*   (= ._.)
*   / >  \>
*/

J:Grand Prix of Ballance

大意:

思路:

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define  vi vector<int>
#define  vii vector<pair<int, int>>
#define ff first 
#define ss second 
// ++   ~!    */+-    <<>>    <>  ==   &^|   &&|| =


void solve()
{
    int n, m, q;cin >> n >> m >> q;
    map<int, bool>st;
    vi v(m + 1);
    int con = -1;

    int score = m;
    while (q --)
    {
        int op;cin >> op;
        if (op == 1)
        {
            cin >> con;
            st.clear();
            score = m;
        }
        if (op == 2)
        {
            int x, y;cin >> x >> y;
            if (y != con || st[x])continue;
            st[x] = true;
            v[x] += score --;
        }
        if (op == 3)
        {
            int x, y;cin >> x >> y;
            if (y != con || st[x])continue;
            st[x] = true;
        }
    }

    vi p(m + 1);
    for (int i = 1; i <= m; i++)p[i] = i;
    sort(p.begin() + 1, p.end(), [&](int a, int b) {
        if (v[a] == v[b])return a < b;
        else return v[a] > v[b];
        });

    for (int i = 1; i <= m; i++)
        cout << p[i] << ' ' << v[p[i]] << endl;
    
}

signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

    int t = 1;
    cin >> t;
    while (t--) solve();

    return 0;
}
/*   /\_/\
*   (= ._.)
*   / >  \>
*/

L:Recover Statistics

大意:

思路:

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define  vi vector<int>
#define  vii vector<pair<int, int>>
#define ff first 
#define ss second 
// ++   ~!    */+-    <<>>    <>  ==   &^|   &&|| =


void solve()
{
    int a, b, c;cin >> a >> b >> c;
    cout << 100 << endl;
    for (int i = 1; i <= 50; i ++)
        cout << a << ' ';
    for (int i = 51; i <= 95; i ++)
        cout << b << ' ';
    for (int i = 96; i <= 99; i++)
        cout << c << ' ';
    cout << c + 1;
    
}

signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

    int t = 1;
   // cin >> t;
    while (t--) solve();

    return 0;
}
/*   /\_/\
*   (= ._.)
*   / >  \>
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值