Educational Codeforces Round 81 (Rated for Div. 2)

A~Dhttps://www.cnblogs.com/GoodVv/p/12249839.html

因为懒所以 A ~ D 拿给VV写了 ʅ(‾◡◝)ʃ

但是我的代码还是会放上的(思路可能和VV博客里写的不一样)

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    cin >> t;
    while(t --)
    {
        int n ;
        cin >> n;
        if(n & 1) cout << 7 , n -= 3;
        for(int i = 1 ; i <= n / 2 ; i ++) cout << 1;
        cout << '\n';
    }
    return 0;
} 
A - Display The Number
#include<bits/stdc++.h>
using namespace std;
#define ll long long
map<ll , ll>cnt;
ll n , x , ans , sum;
string s;
int main()
{
    ll t;
    cin >> t;
    while(t --)
    {
        cnt.clear();
        ans = sum = 0; 
        cin >> n >> x >> s;
        if(x == 0) ans = 1;
        for(auto i : s)
        {
            if(i - '0') sum --;
            else           sum ++;
            cnt[sum] ++;
        }
        if(!sum)
        {
            if(!cnt[x]) cout << 0 << '\n';
            else         cout << -1 << '\n';
            continue ;
        }
        for(auto it : cnt)
            if(abs(it.first - x) % (sum) == 0)
            {
                if((x > it.first && sum < 0) || (x < it.first && sum > 0)) continue;
                ans += it.second;
            }
        cout << ans << '\n';
    }
    return 0;
} 
   
B - Infinite Prefixe
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
const int N = 1e5 + 10;
int pos[N][27];
char s[N] , t[N];
int main()
{
    int T;
    cin >> T;
    while(T --)
    {
        cin >> s + 1 >> t + 1;
        int len1 = strlen(s + 1) , len2 = strlen(t + 1);
        for(int j = 0 ; j < 26 ; j ++) pos[len1][j] = inf;
        for(int i = len1 - 1; i >= 0 ; i --)
        {
            for(int j = 0 ; j < 26 ; j ++)
                pos[i][j] = pos[i + 1][j];
            pos[i][s[i + 1] - 'a'] = i + 1;
        }
        int now = 1 , flag = 1 , ans = 0;
        while(now <= len2)
        {
            if(pos[0][t[now] - 'a'] == inf) { flag = 0 ; break ; }
            int idx = pos[0][t[now] - 'a'];
            while(idx != inf && now <= len2)
            now ++ , idx = pos[idx][t[now] - 'a'];
            ans ++ ;
        }
        if(!flag) cout << -1 << '\n';
        else cout << ans << '\n';
    }
    return 0;
}
C - Obtain The String
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e5 + 10;
ll eular(ll n)
{
    ll ans = n;
    for(ll i = 2; i * i <= n ; i ++)
    {
        if(n % i == 0)
        {
            ans = ans / i * (i - 1);
            while(n % i == 0)
                n /= i;
        }
    }
    if(n > 1) ans = ans / n * (n - 1);
    return ans;
}
int main()
{
    int t;
    cin >> t;
    while(t --)
    {
        ll a , b;
        cin >> a >> b;
        ll gcdd = __gcd(a , b);
        b /= gcdd;
        cout << eular(b) << '\n';
    }
    return 0;
}
 
D - Same GCDs

 

E. Permutation Separation

题目链接:https://codeforces.com/contest/1295/problem/E

题意:

  给你一个长度为n的数组,其中 1 ~ n 每个数恰好在该数组中出现一次,并且每个数都有自己的价值 ai

  你要在数组中任意位置切一刀使数组划分为左集合和右集合(刚切完左右集合不得为空)

  切完后你可以将一个集合的任意一个元素 x 丢到另一个集合去,但是你需要支付 a[x]的代价

  现要使操作结束后右集合的元素均大于左集合的元素(或其中任意一集合为空集),问你最小代价是多少

分析:

  先模拟一遍

  假设 n = 6,数组的元素分别为 3,6,5,4,1,2 ,那么我们可以切的位置分别有3,6、6,5、5,4、4,1、1,2之间

  我们将每一个可以切的间隙从左往右进行编号,并定义为切点,如图所示:

 

  其中 1 左边的切点有①②③④,右边的切点有⑤

  2 左边的切点有①②③④⑤,右边没有切点

  3 左边没有切点,右边的切点有①②③④⑤

  ......

  在开始之前,我们还要知道当我们操作完之后,左集合要么为空,要么剩余 m 个元素,而剩余的元素分别是1 ~ m

  好了在了解完以上后,我们采用边枚举边更新的方法

  首先,让我们用pos[i] 表示第 i 个元素的位置,其中pos[1] = 5,pos[2] = 6,pos[3] = 1...

  用sum[i] 表示前 i 个位置的代价前缀和,其意义是将切点 i 左边的数全移至右边所付出的代价

  初始我们先让第 i 个切点的代价为sum[i] , 即在切完之后将左边所有数都移至右集合。

  我们用线段树维护每个切点的花费(第 i 个位置(区间)维护第 i 个切点),然后我们开始对每个元素进行枚举

  one首先是元素 1  , pos[1] = 5 , 我们观察第五个元素右边的切点有⑤ , 左边的切点有①②③④

  对于右边的切点⑤:它当前的花费为sum[5] ,包括了元素1的代价,但实际上在切完⑤之后元素1在左集合,且我们并不需要把元素1移至右边,所以我们把切点⑤的花费减去元素1的代价

  对于左边的切点:在切完之后元素1是处于集合的右边,所以开始的时候sum[1],sum[2],sum[3],sum[4]并没有算上元素1右移的代价

  而实际上元素1应该要移至左集合,所以我们把切点①~④的花费加上元素1的代价

  two然后是元素2, pos[2] = 6 , 第六个元素右边没有切点,左边的切点有①②③④⑤

  对于右边的切点:无。

  对于左边的切点:切完之后元素2是处于集合的右边,所以开始的时候sum[1],sum[2],sum[3],sum[4],sum[5]并没算上元素2右移的代价

  而实际上元素2应该要移至左集合,所以我们把切点①~⑤的花费加上元素2的代价

  three紧接着是元素3,pos[3] = 1,第一个元素的左边没有切点,右边的切点有①②③④⑤

  对于右边的切点:在切完之后元素3是处于集合的左边,且我们并不需要把元素3右移。

  但在初始的时候我们统一把左集合的全都右移了,所以初始的时候切点①②③④⑤的花费都算上元素3的代价,所以我们要把他们的花费减去元素3的代价

  对于左边的切点:无。

  ......

  根据以上我们发现,对于第 i 次枚举(元素 i )编号为 1 ~ pos[i] - 1 的切点(元素 i 的右边)花费都要减去 i 的代价,而编号 pos[i] ~ n - 1的切点(元素i的左边)花费都要加上 i 的代价

  这只要用线段树区间更新一波就可以把复杂度降至 logn,在加上枚举的时间消耗,总复杂度为 nlogn . 完全OK

  ans 的值我们在每次枚举完更新

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
const int N = 2e5 + 10;
struct Segment_Tree{
    ll l , r;
    ll minn , lazy;
}tree[N << 2];
void build(ll l , ll r , ll rt , ll *aa)
{
    tree[rt].l = l , tree[rt].r = r;
    if(l == r)
    {
        tree[rt].minn = aa[l];    
        return ;
    }
    ll mid = l + r >> 1;
    build(l , mid , rt << 1 , aa);
    build(mid + 1 , r , rt << 1 | 1 , aa);
    tree[rt].minn = min(tree[rt << 1].minn , tree[rt << 1 | 1].minn);
}
void push_down(ll rt)
{
    if(tree[rt].lazy)
    {
        tree[rt].minn += tree[rt].lazy;
        tree[rt << 1].minn += tree[rt].lazy;
        tree[rt << 1 | 1].minn += tree[rt].lazy;
        tree[rt << 1].lazy += tree[rt].lazy;
        tree[rt << 1 | 1].lazy += tree[rt].lazy;
        tree[rt].lazy = 0;
    }
} 
void update_range(ll L , ll R , ll val , ll rt)
{
    if(tree[rt].r < L || tree[rt].l > R) return ;
    if(L <= tree[rt].l && R >= tree[rt].r)
    {
        tree[rt].lazy += val;
        tree[rt].minn += val;
        return ;
    }
    push_down(rt);
    ll mid = tree[rt].l + tree[rt].r >> 1;
    if(L <= mid)
    update_range(L , R , val , rt << 1);
    if(R > mid)
    update_range(L , R , val , rt << 1 | 1);
    tree[rt].minn = min(tree[rt << 1].minn , tree[rt << 1 | 1].minn);
}
ll query_min(ll L , ll R , ll rt)
{
    if(L <= tree[rt].l && R >= tree[rt].r)
    return tree[rt].minn;
    push_down(rt);
    ll mid = tree[rt].l + tree[rt].r >> 1;
    ll res1 = (0x3f3f3f3f3f3f3f3fll) , res2 = (0x3f3f3f3f3f3f3f3fll);
    if(L <= mid)
    res1 = query_min(L , R , rt << 1);
    if(R > mid)
    res2 = query_min(L , R , rt << 1 | 1);
    return min(res1 , res2);
}
ll a[N] , pos[N] , sum[N];
int main()
{
    int n ;
    cin >> n;
    for(int i = 1 ; i <= n ; i ++)
    {
        int x ; cin >> x;
        pos[x] = i;
    }
    for(int i = 1 ; i <= n ; i ++)
    cin >> a[i] , sum[i] = sum[i - 1] + a[i];
    build(1 , n - 1 , 1 , sum);
    ll ans = min(a[1] , a[n]);
    for(int i = 1 ; i <= n - 1 ; i ++)
    {
        update_range(pos[i] , n - 1 , -a[pos[i]] , 1);
        update_range(1 , pos[i] - 1 , a[pos[i]] , 1);
        ans = min(ans , query_min(1 , n - 1 , 1));
    }
    update_range(pos[1] , n - 1 , -a[pos[1]] , 1);
    update_range(1 , pos[i] - 1 , a[pos[1]] , 1);
    cout << ans << '\n';
    return 0;
}

 

posted @ 2020-02-01 19:34  GsjzTle  阅读(239)  评论(0编辑  收藏  举报