0
点赞
收藏
分享

微信扫一扫

2022-04-17每日刷题打卡

霸姨 2022-04-17 阅读 46

2022-04-17每日刷题打卡

代码源——每日一题

漂亮数 - 题目 - Daimayuan Online Judge

有一个长度为 n 的数字 X,由 n 位数字组成,即 a1,a2,…an,它们按从左到右的顺序组成一个十进制的数。

并且,你将得到一个数 k,需要你构造出一个最小的数 Y,对于每一位 i(1≤i≤m−k), 满足 bi=bi+k,并且X≤Y。

输入描述
第一行给出两个数 n,k 其中 (2≤n≤200000,1≤k<n)。

第二行给出 X:a1,a2,…an。

输出描述
第一行给出Y的长度 m。

输出最小的满足条件的数 Y:b1,b2,…bm。

输入样例

3 2
353

输出样例

3
353

这题的意思就是说,用一个长度为k的数来组成一个数y,使得y大于等于x。

为什么是长度为k的数?因为你第i个数和第k+i个数相同,我们就可以把它看作是一个长度为k的轮回,即用一个长度为k的数组成y。

首先先从x处获取前k个数组成y。然后拿y来和x比较(k个数k个数的比),当有个位置上x[i]大于y[i]时,我们给y的最小位+1。因为我们要保证y组成的n个数大于等于x,如果在相同位时x有一个数大于y,那显然是不成立的,所以我们要修改y的值,那么为什么我们要修改的是最低位的值?这里要举个例子说明:

比如x是354365,k是3,那么我们得到的y是354,和x开始k个数k个数的比较,因为我们是从x获取的前k个数,所以下标0k-1这一段是完全相同的。然后我们看后面的365和y比,第二位上6比y的5大,如果我们修改第二位,把它变成6,这样y就变成了364,最后组成的数是364364,而如果我们修改的是最小位的,4变成5,则最后会是355355。显然要比前面那个小。就像我们说的,下标0k-1这一段是完全相同的,第一次比较的最低位对于后面比较的任何一位都是高位数,所以修改了这一位后,后面我们就可以不用管了,毕竟高位上已经比x大了,后面数为何种情况都不会使得x大于y。

说人话就是,我们在比较的过程中,只要有一位是x比y大,那我们直接给y最低位+1就可以了,而且经过这一步操作后就直接结束比较。

那么有没有可能最后组成的数会比x还多一位呢?当然是不可能的,比较x可以等于y,不管怎么样,我们最多把每一位都变成9,那么无论如何都能满足y大于等于x的,没必要多一位。

#include<iostream>
using namespace std;
#include<cstdio>
#include<algorithm>
#include<set>
#include<string>
#include<unordered_map>
#include<vector>

int main() {
    int n, k;
    cin >> n >> k;
    vector<int>x(n), y(k);
    string s;
    cin >> s;
    bool flag = true;
    for (int i = 0; i < n; i++)
    {
        x[i] = s[i] - '0';
        if (i < k)y[i] = x[i];
    }
    flag = false;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < k; j++)
        {
            if (y[j] < x[i + j])
            {
                int ans = k - 1;
                while (y[ans] == 9)ans--;
                y[ans]++;
                for (int l = ans + 1; l < k; l++)y[l] = 0;
                flag = true;
                break;
            }
            else if (y[j] > x[i + j])
            {
                flag = true;
                break;
            }
        }
        i += k - 1;
        if (flag)break;
    }
    cout << n << endl;
    for (int i = 0; i < n; i++)
    {
        cout << y[i % k];
    }
    return 0;
}

CodeForces——线段树专题

D - Segment Tree, part 1 - D. Intersecting Segments

Given an array of 2n numbers, each number from 1 to n in it occurs exactly twice. We say that the segment y intersects the segment x if exactly one occurrence of the number y is between the occurrences of the number x. Find for each segment i how many segments there are that intersect with it.

Input
The first line contains the number n (1≤n≤105), the second line contains 2n numbers. It is guaranteed that every number from 1 to n occurs exactly twice.

Output
Print n numbers, the i-th number is equal to the number of segments that intersect with the segment i.

Example
input

5
5 1 2 2 3 1 3 4 5 4

output

1 0 1 1 1 

这题意思是说,给你一个数组,这个数组长度为2n,元素都由两个1~n的数组成,每两个相同的树组成一个段,问你每个段和多少个段相交。相交意思是说,有一个的段的一个端点在你的段里,另一个端点不在,比如5和4就是相交,但5和1不是。

这里我们要进行两次计算,第一次从左往右,计算左端点在,右端点不在的情况,第二次从右往左,计算右端点在,左端点不在的情况。

用到的线段树是单点修改+区间和,一开始线段树全为0。第一次先记录下每个左端点的坐标,当遍历到左端点时,在线段树里把对应位置变成1,当遍历到右端点时,计算左端点到右端点的区间和,这个区间和就是与多少个段相交。并且计算完区间和后把左端点的值变成0。

为什么区间和可以表示与多少个段相交?因为就像我们说的,遍历到左端点才会把值从0变成1,而我们遇到右端点后又会变成0,我们左端点到右端点的区间和为多少,就说明有多少个段左端点在我们区间内,但右端点不在(如果在那左端点也该是0)。正好是相交的规定。但这个方法只能算左端点到在段内的情况,所以我们还要从右往左遍历一趟,计算右端点在左端点不在的情况。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n';
typedef long long ll;
typedef pair<int, int> PII;
const int N = 300050;
int f[4 * N], a[N], n,b[N];

void revise(int k, int l, int r, int x,int y)
{
    if (l == r)
    {
        f[k] += y;
        return;
    }
    int m = (l + r) / 2;
    if (x <= m)revise(k + k, l, m, x, y);
    else
        revise(k + k + 1, m + 1, r, x, y);
    f[k] = f[k + k] + f[k + k + 1];
}

int calc(int k, int l, int r, int x, int y)
{
    if (l == x && y == r)
    {
        return f[k];
    }
    int m = (l + r) / 2;
    if (y <= m)return calc(k + k, l, m, x, y);
    else
        if (x > m)return calc(k + k + 1, m + 1, r, x, y);
        else return calc(k + k , l, m, x, m) + calc(k + k+1, m + 1, r, m + 1, y);
}

int main()
{
    unordered_map<int, int>mymap;
    map<int, int>cnt;
    cin >> n;
    vector<int>v(n);
    for (int i = 1; i <= 2*n; i++)
    {
        cin >> a[i];
        if (mymap[a[i]] == 0)mymap[a[i]] = i;
    }
    for (int i = 1; i <= 2*n; i++)
    {
        if (cnt[a[i]] == 0)
        {
            cnt[a[i]] = 1;
            revise(1, 1, 2 * n, mymap[a[i]], 1);
        }
        else
        {
            revise(1, 1, 2 * n, mymap[a[i]], -1);
            v[a[i]-1] = calc(1, 1, 2*n, mymap[a[i]], i);
        }
    }
    int ans = n;
    int l = 1, r = 2 * n;
    while (l < r)
    {
        swap(a[l], a[r]);
        l++, r--;
    }
    memset(f, 0, sizeof f);
    mymap.clear();
    cnt.clear();
    for (int i = 1; i <= 2 * n; i++)
    {
        if (mymap[a[i]] == 0)mymap[a[i]] = i;
    }
    for (int i = 1; i <= 2 * n; i++)
    {
        if (cnt[a[i]] == 0)
        {
            cnt[a[i]] = 1;
            revise(1, 1, 2 * n, mymap[a[i]], 1);
        }
        else
        {
            revise(1, 1, 2 * n, mymap[a[i]], -1);
            v[a[i] - 1] += calc(1, 1, 2 * n, mymap[a[i]], i);
        }
    }
    for (auto i : v)cout << i << " ";
    return 0;
}
举报

相关推荐

2022-01-17每日刷题打卡

2022-01-04每日刷题打卡

2022-04-19每日刷题打卡

2022-04-17 周总结

0 条评论