Educational Codeforces Round 126 (Rated for Div. 2)

A. Array Balancing
 

You are given two arrays of length nn: a1,a2,,ana1,a2,…,an and b1,b2,,bnb1,b2,…,bn.

You can perform the following operation any number of times:

  1. Choose integer index ii (1in1≤i≤n);
  2. Swap aiai and bibi.

What is the minimum possible sum |a1a2|+|a2a3|++|an1an||a1−a2|+|a2−a3|+⋯+|an−1−an| +|b1b2|+|b2b3|++|bn1bn||b1−b2|+|b2−b3|+⋯+|bn−1−bn| (in other words, i=1n1(|aiai+1|+|bibi+1|)∑i=1n−1(|ai−ai+1|+|bi−bi+1|)) you can achieve after performing several (possibly, zero) operations?

Input

The first line contains a single integer tt (1t40001≤t≤4000) — the number of test cases. Then, tt test cases follow.

The first line of each test case contains the single integer nn (2n252≤n≤25) — the length of arrays aa and bb.

The second line of each test case contains nn integers a1,a2,,ana1,a2,…,an (1ai1091≤ai≤109) — the array aa.

The third line of each test case contains nn integers b1,b2,,bnb1,b2,…,bn (1bi1091≤bi≤109) — the array bb.

Output

For each test case, print one integer — the minimum possible sum i=1n1(|aiai+1|+|bibi+1|)∑i=1n−1(|ai−ai+1|+|bi−bi+1|).

题意:给两个等长的数列a和b,可以任意交互某个位置的a[i]和b[i],使得两个数组所有的【前项与后项的差 的绝对值】之和最小。

思路:对于每一个位置,它是否要交换一下,只要考虑它和下一项的作差哪种情况更小。也就是对于i来说,只要考虑是换了之前(a[i+1]-a[i] + b[i+1]-b[i])还是换了之后(a[i+1]-b[i] + b[i+1]-a[i])哪个更小就可以,一个简单的贪心。

有人说交换一下,对它和它前一项的差不是也会有影响的吗?其实没影响,只要前面的所有项跟着一起全换一下就行了。

#include<bits/stdc++.h>
using namespace std;
#define ll long long

int main()
{
    int a[50], b[50];
    int T, n;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        for(int i=0;i<n;i++)
            scanf("%d", a+i);
        for(int i=0;i<n;i++)
            scanf("%d", b+i);
        ll sum = 0;
        for(int i=1;i<n;i++)
        {
            sum += min(abs(a[i]-a[i-1])+abs(b[i]-b[i-1]), abs(a[i]-b[i-1])+abs(b[i]-a[i-1]));
        }
        printf("%lld\n", sum);
    }
}
B. Getting Zero

Suppose you have an integer vv. In one operation, you can:

  • either set v=(v+1)mod32768
  • or set v=(2v)mod32768

You are given nn integers a1,a2,,ana1,a2,…,an. What is the minimum number of operations you need to make each aiai equal to 00?

Input

The first line contains the single integer nn (1n327681≤n≤32768) — the number of integers.

The second line contains nn integers a1,a2,,ana1,a2,…,an (0ai<327680≤ai<32768).

Output

Print nn integers. The ii-th integer should be equal to the minimum number of operations required to make aiai equal to 00.

 

题意:给一个数,能对它做两个操作:1、加1取模32768,2、乘以2取模32768。问最少操作几次可以让这个数变成32768。

思路:32768就是2的15次方,也就是说不管你原来的数是多少,最多乘15个2,就能整除32768了。如果数的因子有若干个2,还能少乘几次。所以简单的遍历一下,枚举每个数字+1的操作,然后看再乘2几次能满足,反正最多不能超过15次。

这里0要特判一下,没想到被卡了很久Orz

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod =  32768; // 2^15
int n;

int main()
{
    int T;
    scanf("%d", &T);
    
    while(T--)
    {
        scanf("%d", &n);
        if(!n) 
        {
            printf("0\n"); continue;
        }
    
        int t = 0, nn = n;
        while(nn && nn%2 == 0)
        {
            t += 1;
            nn /= 2;
        }
        int ans = 15-t;
        for(int i=1;i<16;i++)
        {
            int tp = n+i;
            t = 0;
            while(tp && tp%2 == 0)
            {
                t += 1;
                tp /= 2;
            }
            if(15-t+i < ans)
                ans = 15-t+i;
        }
        
        printf("%d\n", ans);
    }
}

C. Water the Trees

There are nn trees in a park, numbered from 11 to nn. The initial height of the ii-th tree is hihi.

You want to water these trees, so they all grow to the same height.

The watering process goes as follows. You start watering trees at day 11. During the jj-th day you can:

  • Choose a tree and water it. If the day is odd (e.g. 1,3,5,7,1,3,5,7,…), then the height of the tree increases by 11. If the day is even (e.g. 2,4,6,8,2,4,6,8,…), then the height of the tree increases by 22.
  • Or skip a day without watering any tree.

Note that you can't water more than one tree in a day.

Your task is to determine the minimum number of days required to water the trees so they grow to the same height.

You have to answer tt independent test cases.

Input

The first line of the input contains one integer tt (1t21041≤t≤2⋅104) — the number of test cases.

The first line of the test case contains one integer nn (1n31051≤n≤3⋅105) — the number of trees.

The second line of the test case contains nn integers h1,h2,,hnh1,h2,…,hn (1hi1091≤hi≤109), where hihi is the height of the ii-th tree.

It is guaranteed that the sum of nn over all test cases does not exceed 31053⋅105 (n3105∑n≤3⋅105).

Output

For each test case, print one integer — the minimum number of days required to water the trees, so they grow to the same height.

题意:有一串树,每天给树浇水它就能长高,但是一天只能浇一棵。如果是奇数天,浇水会长高1,如果是偶数天,浇水会长高2。问最少要几天让所有树长得一样高。

思路:贪心一下。对同一棵树来说,能让它长高2的,就不用两个1去让它长了(长高2花费2天,长高两个1花费3天)。所以我们找到最高的树,看一下每个树距离它有几个1、几个2(尽可能多的放2)。用c1表示1的个数,c2表示2的个数,这样的话就是c1*2-1天或者c2*2天中取大的那个就能长完。但是如果2很多很多,远超1的数量,是不是把2分解为两个1,c1的个数也还是比c2小呢?所以我们可以尽可能平均分配的把2裂开成1,也就是c2和c1的差一个增加2/3一个减少1/3就行了。

还有这里要考虑是不是最高的树再长个1,会对大家都好。以及这个题要注意longlong……我的习惯真的太差了(泪)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
const int maxn = 3e5+7;
ll arr[maxn];
ll solve(ll maxx, int n)
{
    ll ret = -1, c1 = 0, c2 = 0;
    for(int i=0;i<n;i++)
    {
        ll sub = maxx - arr[i];
        if(sub&1) c1 ++;
        c2 += sub / 2;
    }
    ret = max(c1*2ll-1, c2*2ll);
    if(c1 < c2)
    {
        ll sub = (c2-c1+1)/ 3;
        c2 -= sub;
        c1 += sub*2;
        ret = min(ret, max(c1*2ll-1, c2*2ll));
    }
    return ret;
}
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int n;
        ll c1 = 0, c2 = 0;
        scanf("%d", &n);
        ll maxx = -1;
        for(int i=0;i<n;i++)
        {
             scanf("%lld", arr+i);
             if(arr[i] > maxx) maxx = arr[i];
        }
        ll ans = min(solve(maxx, n), solve(maxx+1, n));
        
        printf("%lld\n", ans);
    }
}

 D(补)

D. Progressions Covering
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given two arrays: an array aa consisting of nn zeros and an array bb consisting of nn integers.

You can apply the following operation to the array aa an arbitrary number of times: choose some subsegment of aa of length kk and add the arithmetic progression 1,2,,k1,2,…,k to this subsegment — i. e. add 11 to the first element of the subsegment, 22 to the second element, and so on. The chosen subsegment should be inside the borders of the array aa (i.e., if the left border of the chosen subsegment is ll, then the condition 1ll+k1n1≤l≤l+k−1≤n should be satisfied). Note that the progression added is always 1,2,,k1,2,…,k but not the k,k1,,1k,k−1,…,1 or anything else (i.e., the leftmost element of the subsegment always increases by 11, the second element always increases by 22 and so on).

Your task is to find the minimum possible number of operations required to satisfy the condition aibiai≥bi for each ii from 11 to nn. Note that the condition aibiai≥bi should be satisfied for all elements at once.

Input

The first line of the input contains two integers nn and kk (1kn31051≤k≤n≤3⋅105) — the number of elements in both arrays and the length of the subsegment, respectively.

The second line of the input contains nn integers b1,b2,,bnb1,b2,…,bn (1bi10121≤bi≤1012), where bibi is the ii-th element of the array bb.

Output

Print one integer — the minimum possible number of operations required to satisfy the condition aibiai≥bi for each ii from 11 to nn.

思路:线段树+差分维护

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
const int maxn = 3e5+7;
ll n, k, a[maxn];

struct tree{
    ll l, r;
    ll val, lazy;
}t[maxn << 2];

void pushup(ll p)
{
    t[p].val = t[p<<1].val + t[p<<1|1].val;
}

void pushdown(ll p)
{
    if(t[p].lazy == 0) return ;
    t[p<<1].val += (t[p<<1].r-t[p<<1].l+1) * t[p].lazy;
    t[p<<1].lazy += t[p].lazy;
    t[p<<1|1].val += (t[p<<1|1].r-t[p<<1|1].l+1) * t[p].lazy;
    t[p<<1|1].lazy += t[p].lazy;
    t[p].lazy = 0;
}
void build(ll p, ll l, ll r)
{
    t[p].l = l; t[p].r = r; // current point corredspond l/r position
    if(l == r) {
        t[p].val = a[l] - a[l-1];  // save difference
        return ;
    }
    ll mid = l + r >> 1;
    build(p << 1, l, mid);
    build(p << 1 | 1, mid+1, r);
    pushup(p);
}
void update(ll cl, ll cr, ll p, ll val)
{
    if(t[p].l >= cl && t[p].r <= cr) // treerange belong to queryrange
    {
        t[p].lazy += val;
        t[p].val += (t[p].r-t[p].l+1)*val;
        return ;
    }
    pushdown(p);
    ll mid = t[p].l + t[p].r >> 1;
    if(mid >= cl) update(cl, cr, p<<1, val); // update left sub tree
    if(mid < cr) update(cl, cr, p<<1|1, val); // update right sub tree
    pushup(p);
}

ll query(ll cl, ll cr, ll p)
{
    if(t[p].l >= cl && t[p].r <= cr) return t[p].val;
    pushdown(p);
    ll mid = t[p].l + t[p].r >> 1;
    ll res = 0;
    if(mid >= cl) res += query(cl, cr, p<<1);
    if(mid < cr) res += query(cl, cr, p<<1|1);
    return res;
}

int main()
{
    ll l, r;
    ll ans = 0;
    scanf("%lld%lld", &n, &k);
    for(ll i=1;i<=n;i++)
        scanf("%lld", a+i);
    build(1, 1, n);
    for(ll i=n; i>= 1; i--) // 逆序遍历差值 
    {
        ll now = query(1, i, 1); // t[i] - t[0], 代表i-th位置的值 
        if(now <= 0) continue;   // 已经合法 
        ll div = min(i, k);      // 区间必须放得下 
        ll rd = (now-1) / div + 1;  // 把这个值减到0最少要减几轮
        ans += rd;
        update(i-div+1, i, 1, -rd); // 对每个点每次-1,减rd次,就是在这片区间每个点-rd 
    }
    printf("%lld\n", ans);
}

 

posted @ 2022-04-11 17:36  HazelNuto  阅读(73)  评论(0编辑  收藏  举报