The 2022 ICPC Asia Shenyang Regional Contest(2022 沈阳 CDFHIL)

Problem D. DRX vs. T1
题意:问谁能赢这个bo5
code

void solve(){
    string s;
    cin >> s;
    int t, d, m;
    t = d = m = 0;
    for(auto i : s)
        if(i == 'T')
            t ++;
        else if(i == 'D') d ++;
        else m ++;
    if(t == 3)
        cout << "T1" << endl;
    else cout << "DRX" << endl; 
}

Problem C. Clamped Sequence
题意:设定一个区间,求 ∑ a b s ( a [ i ] − a [ i + 1 ] ) \sum{abs(a[i]-a[i+1])} abs(a[i]a[i+1])
思维:以每个 a i a_i ai 分别为上下界,求max就行

code

#define rep(a,b,c) for(int a=b;a<=c;a++)
const int N = 1e6 + 10;
int a[N], b[N];
int n, m;
 
void solve(){
    cin >> n >> m;
    rep(i,1,n)
        cin >> a[i];
    int ans = 0;
    rep(i,1,n){
        int res = 0;
        int l = a[i] - m, r = a[i];
        rep(j,1,n){
            if(a[j] < l)
                b[j] = l;
            else if(a[j] > r)
                b[j] = r;
            else b[j] = a[j];
        }
        rep(i,2,n)
            res += abs(b[i] - b[i - 1]);
        ans = max(ans, res);
        res = 0;
        l = a[i], r = a[i] + m;
        rep(j,1,n){
            if(a[j] < l)
                b[j] = l;
            else if(a[j] > r)
                b[j] = r;
            else b[j] = a[j];
        }
        rep(i,2,n)
            res += abs(b[i] - b[i - 1]);
        ans = max(ans, res);
    }
    cout << ans << endl;
}
 

Problem L. Tavern Chess
题意:(读题喵,读不懂题就似了喵)
思路:模拟,就dfs暴力模拟这个过程就完了

code

const int N = 10;
struct Node
{
    int x, y;
    int sum = 0;
}a[N], b[N];
int n, m;
long double q, w, e;
 
bool check(long double res){
    int st1, st2;
    st1 = st2 = 0;
    rep(i,0,n - 1){
        if(a[i].y > 0){
            st1 = 1;
        }
    }
    rep(i,0,m - 1){
        if(b[i].y > 0){
            st2 = 1;
        }
    }
 
    if(st1 && st2)
        return 1;
 
    if(!st1 && !st2)
        e += res;
    else if(!st1)
        w += res;
    else if(!st2) 
        q += res;
    return 0;
}
 
void dfs(int u, long double res){
    if(u == 1){
        int minn = INF, idx1;
        rep(i, 0, n - 1){
            if(a[i].sum < minn && a[i].y > 0){
                minn = a[i].sum;
                idx1 = i;
            }
        }
        a[idx1].sum ++;
        long double k = 0;
        rep(i, 0, m - 1){
            if(b[i].y > 0)
                k += 1;
        }
        res = res / k;
        
        rep(i,0,m - 1){
            if(b[i].y <= 0) continue;
 
            a[idx1].y -= b[i].x;
            b[i].y -= a[idx1].x;
 
            if(check(res))
                dfs(2, res);
 
            a[idx1].y += b[i].x;
            b[i].y += a[idx1].x;
        }
        a[idx1].sum --;
    }
    else{
        int minn = INF, idx1;
        rep(i, 0, m - 1){
            if(b[i].sum < minn && b[i].y > 0){
                minn = b[i].sum;
                idx1 = i;
            }
        }
        b[idx1].sum ++;
 
        long double k = 0;
        rep(i, 0, n - 1){
            if(a[i].y > 0)
                k += 1;
        }
        res = res / k;
        rep(i,0,n - 1){
            if(a[i].y <= 0) continue;
            b[idx1].y -= a[i].x;
            a[i].y -= b[idx1].x;
 
            if(check(res))
                dfs(1, res);
 
            b[idx1].y += a[i].x;
            a[i].y += b[idx1].x;
        }
        b[idx1].sum --;
    }
}
 
void solve(){
    cin >> n >> m;
    rep(i,0,n - 1){
        int k; cin >> k;
        a[i].x = a[i].y = k;
    }
    rep(i,0,m - 1){
        int k; cin >> k;
        b[i].x = b[i].y = k;
    }
 
    if(n > m){
        dfs(1, 1.0);
    }
    else if(m > n){
        dfs(2, 1.0);
    }
    else{
        dfs(1, 0.5);
        dfs(2, 0.5);
    }
 
    cout << q << endl << w << endl << e << endl;
}

Problem F. Half Mixed
题意:构造一个n行m列的矩阵,纯子矩阵的数量等于混合子矩阵的数量,纯子矩阵就是全1或者全0,混合子矩阵就是01都有
思路:
首先是 N O NO NO的情况:子矩阵个数总共有 n ∗ ( n + 1 ) 2 ∗ m ∗ ( m + 1 ) 2 \frac{n * (n+1)}{2}*\frac{m*(m+1)}{2} 2n(n+1)2m(m+1) 个,所以这个数如果是计数肯定就不行了
然后是 Y E S YES YES 的情况
选择一个 x ∗ ( x + 1 ) 2 \frac{x * (x+1)}{2} 2x(x+1) 是偶数的边
假设同色的长度分别为 l e n 1 , l e n 2 . . . . len_1,len_2.... len1,len2....,那么对于一个 1 ∗ x 1*x 1x的矩形来说,纯色子区间的个数是 ∑ i = 1 l e n i ∗ ( l e n i + 1 ) 2 \sum_{i = 1}\frac{len_i * (len_i + 1)}{2} i=12leni(leni+1)
从大到小枚 l e n i len_i leni,满足以下两点
1、 ∑ l e n i = m \sum len_i=m leni=m
2、 ∑ i = 1 l e n i ∗ ( l e n i + 1 ) 2 = x ∗ ( x + 1 ) 4 \sum_{i = 1}\frac{len_i * (len_i + 1)}{2} = \frac{x*(x+1)}{4} i=12leni(leni+1)=4x(x+1)

code

#define rep(a,b,c) for(int a=b;a<=c;a++)
#define dec(a,b,c) for(int a=b;a>=c;a--)
const int N = 1e6 + 10;
int n, m;
int a[N], g[N];
 
void init(){
    rep(i,1,N - 5)
        a[i] = i * (i + 1) / 2;
}
 
void solve(){
    cin >> n >> m;
    if((n * (n + 1) / 2 * m * (m + 1) / 2) & 1 || ((n * (n + 1) / 2 & 1) && (m * (m + 1) / 2 & 1))){
        cout << "No" << endl;
        return;
    }
    cout << "Yes" << endl;
    if((n * (n + 1) / 2) % 2 == 0){
        int k = n * (n + 1) / 4 - n, sum = 0;
 
        vector<int> v;
        dec(i,n,1){
            if(k == 0)
                break;
            int num = k / a[i];
            rep(j,1,num){
                sum += i + 1;
                v.pb(i + 1);
            }
            k %= a[i];
        }
        sum = n - sum;
        rep(i,1,sum)
            v.pb(1);
        int st = 0;
        int idx = 1;
 
        for(auto i : v){
            rep(j, 0, i - 1){
                rep(k, 1, m){
                    g[(idx + j - 1) * m + k] = st;
                }
            }
            idx += i;
            st ^= 1;
        }
        rep(i,1,n)
            rep(j,1,m)
                cout << g[(i - 1) * m + j] << " \n"[j == m];
    }
    else{
        int k = m * (m + 1) / 4 - m, sum = 0;
 
        vector<int> v;
        dec(i,m,1){
            int num = k / a[i];
            rep(j,1,num){
                sum += i + 1;
                v.pb(i + 1);
            }
            k %= a[i];
            if(!k) break;
        }
        sum = m - sum;
        rep(i,1,sum)
            v.pb(1);
 
        int idx = 1, st = 0;
        for(auto i : v){
            rep(j,0,i - 1){
                rep(k,1,n)
                    g[(k - 1) * m + idx + j] = st;
            }
            idx += i;
            st ^= 1;
        }
        rep(i,1,n)
            rep(j,1,m)
                cout << g[(i - 1) * m + j] << " \n"[j == m];
    }
}

Problem I. Quartz Collection
题意:alice和bob两个人选石头,每个人需要n种石头
下面有n种石头的两种价格,先是alice选一个,然后是bob和alice轮流选,每人选两个,直到最后剩一个,谁少给谁
问alice的集齐n种石头的最小花费

思路:
首先是考虑先选,优先选择的人收益最大,否则亏损最大
假设alice全选的 a i a_i ai,那么选 b i b_i bi 的话就是 ∑ a i − a i + b i \sum a_i -a_i+b_i aiai+bi
所以用线段树维护这个 b i − a i b_i-a_i biai ,优先取负值
每个人可以取值两次,第一次和第二次取值的次数相邻,但是当前回合的第一次和下一回合的第一次相隔4次,所以需要 m o d    4 \mod 4 mod4
然后单调修改,区间查询的权值线段树

code

#define int long long
#define p1 (p << 1)
#define p2 (p << 1 | 1)
 
int ans;
int a[maxn], b[maxn];
 
struct seg
{
    int l, r, siz, sum[4];
} tr[maxn << 3];
 
void pushup(int p)
{
    tr[p].siz = tr[p1].siz + tr[p2].siz;
    for (int i = 0; i < 4; i++)
        tr[p].sum[i] = tr[p1].sum[i];
    for (int i = 0; i < 4; i++)
        tr[p].sum[(i + tr[p1].siz) % 4] += tr[p2].sum[i];
}
 
void modify(int p, int l, int r, int x, int op)
{
    if (l == r)
    {
        int i = (tr[p].siz - (op == -1)) % 4;
        tr[p].sum[i] += op * x;
        tr[p].siz += op;
        return;
    }
    else
    {
        int m = (l + r - 1) / 2;
        if (x <= m)
            modify(p1, l, m, x, op);
        else
            modify(p2, m + 1, r, x, op);
        pushup(p);
    }
}
 
void build(int p, int l, int r)
{
    tr[p] = {l, r};
    if (l == r)
        return;
    int m = (l + r - 1) / 2;
    build(p1, l, m);
    build(p2, m + 1, r);
    pushup(p);
}
 
void get()
{
    int siz = tr[2].siz, tp = ans;
    ans -= tr[2].sum[1] + tr[2].sum[2];
    if (siz % 2 == 0)
        ans -= tr[3].sum[1] + tr[3].sum[3];
    else
        ans -= tr[3].sum[0] + tr[3].sum[2];
    cout << ans << '\n';
    ans = tp;
}
 
void solve()
{
    int n, m;
    cin >> n >> m;
    build(1, -maxn, maxn);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i] >> b[i];
        modify(1, -maxn, maxn, a[i] - b[i], 1);
        ans += a[i];
    }
    get();
    while (m--)
    {
        int t, x, y;
        cin >> t >> x >> y;
        ans -= a[t];
        modify(1, -maxn, maxn, a[t] - b[t], -1);
        a[t] = x, b[t] = y;
        ans += a[t];
        modify(1, -maxn, maxn, a[t] - b[t], 1);
        get();
    }
}

Problem H. P-P-Palindrome
题意:给n个字符串,问字符串 s i s_i si和字符串 s j s_j sj的某个前缀首尾拼接而成的字符串是回文串,这个组合有多少个
思路:
利用回文树
构造出回文树之后,枚举边,就可以计算出最小循环节
假设循环节为k,
如果 l e n m o d    k = 0 len\mod k=0 lenmodk=0那么当前回文对答案的贡献是 l e n / k ∗ 2 − 1 len/k*2-1 len/k21
否则对答案的贡献就是1

code

const int N = 1e6 + 10;
int tot = 1;
string s;
struct Node
{
    int fail, ch[26], len;
}tr[N];

int get_fail(int x, int i){
    while(s[i - tr[x].len - 1] != s[i]){
        // cout << x << endl;
        x = tr[x].fail;
    }
    return x;
}

void insert(){
    cin >> s;
    s = " " + s;
    for(int i = 1, p = 0; i < s.size(); i ++){
        // cout << p << endl;
        p = get_fail(p, i);
        if(!tr[p].ch[s[i] - 'a']){
            tr[++ tot].fail = tr[get_fail(tr[p].fail, i)].ch[s[i] - 'a'];
            tr[p].ch[s[i] - 'a'] = tot;
            tr[tot].len = tr[p].len + 2;
        }
        p = tr[p].ch[s[i] - 'a'];
    }
}
 
void solve(){
    tr[0].fail = 1;
    tr[1].len = -1;
    int n;
    cin >> n;
    for(int i = 1; i <= n; i++)
        insert();
    ll ans = 0;
    for(int i = 2; i <= tot; i ++){
        ll k = tr[i].len - tr[tr[i].fail].len;
        if(tr[i].len % k == 0)
            ans += tr[i].len / k * 2 - 1;
        else ans ++;
    } 
    cout << ans << endl;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值