【长期】板刷Codeforces 1500-1700 的构造题

【长期】板刷Codeforces 1500-1700 的构造题

https://codeforces.com/problemset/page/1?tags=constructive+algorithms%2C1500-1700&order=BY_RATING_ASC
每天三道,记录一下
(题意比较明显的,不说了。)

8.18

(1/3,做出第二道)

B. Plus and Multiply

https://codeforces.com/problemset/problem/1542/B
思路:找规律,发现 \(n=a^k + pb\), 即只要找到一个整数 \(p\) 满足等式即可。

#include <bits/stdc++.h>
#define int long long

using namespace std;

void solve () {
    queue <int> q;
    int n, a, b;
    cin >> n >> a >> b;
    if (a == 1) {
        if ((n-1) % b)   cout << "No\n";
        else     cout << "Yes\n";
        return ;
    }

    bool find = false;
    int x = 1;
    while (x <= n) {
        if ((n - x) % b)    x *= a;
        else {
            find = true;
            break;
        }
    }
    if (find)   cout << "Yes\n";
    else    cout << "No\n";
}

signed main () {
    int t;
    cin >> t;
    while (t --) {
        solve ();
    }
}

//Ax+B
//A%a==0,B%b==0
//n=a^k+pb

B. Codeforces Subsequences

https://codeforces.com/problemset/problem/1368/B
多写几项,不难发现"ccooddeforces"这样优先重复出现次数较少的更优,具体见下表:

\(2^1 * 1^9, 2^2 * 1^8, ..., 2^{10} * 1^0 (11,12,...20)\)
\(3^1 * 2^9, 3^2 * 2^8, ..., 3^{10} * 2^0 (21,22,...,30)\)
$4^1 * 3^9, 4^2 * 3^8, ..., 4^{10} * 2^0 (31,32,...,40) $
...
(前面是能构成的满足条件的串的数量,括号里面是串的长度)
大致统计一下就会发现 \(40^{10}\geq 10^{16}\)
因此出答案:

#include <bits/stdc++.h>
#define int long long

using namespace std;

signed main () {
    int n, num1, num2;
    cin >> n;
    string s = "codeforces";
    if (n == 1) {
        cout << "codeforces";
        return 0;
    }
    for (int i = 2; i <= 40; i++) {
        bool find = false;
        for (int j = 1; j <= 10; j++) {
            int x = pow (i, j) * pow (i-1, 10-j);
            if (x >= n) {
                num1 = i, num2 = j;
                find = true;
                break;
            }
        }
        if (find)   break;
    }

    //cout << num1 << ' ' << num2 << endl;

    for (int i = 0; i < 10; i++) {
        for (int j = 1; j < num1; j++) {
            cout << s[i];
        }
        if (i < num2)   cout << s[i];
    }

    //for (int i = 1; i <= 10; i++)   cout << pow(4,i)*pow(3,10-i) << ' ';
    //cout << pow (40, 10);
}

//2^1, 2^2, ..., 2^10 (11,12,...20)  (2,4,8,16,32,64,128,256,512,1024)
//3^1 * 2^9, 3^2 * 2^8, ..., 3^10 * 2^0 (21,22,...,30) (1536 2304 3456 5184 7776 11664 17496 26244 39366 59049)
//4^1 * 3^9, 4^2 * 3^8, ..., 4^10 * 2^0 (31,32,...,40) 
//...

D. Binary String To Subsequences

https://codeforces.com/problemset/problem/1399/D
规则:如果00/11相邻就把他们划分开
上一个屁股后面如果能接上去就接,否则新开一个
模拟题
注意学习写法

#include <bits/stdc++.h>
#define endl "\n"

using namespace std;
typedef pair<int, int> pii;
const int N = 2e5 + 5;
int pos[N];

void solve () {
    int n, k = 0;
    string s;
    cin >> n >> s;

    vector <int> v[2], ans;
    
    for (auto i : s) {
        int x = i - '0';
        if (v[!x].empty()) {
            v[x].push_back (++k);
            ans.push_back (k);
        }
        else {
            ans.push_back (v[!x].back());
            v[x].push_back (v[!x].back());
            v[!x].pop_back();
        }
    }

    cout << k << endl;
    for (auto i : ans)  cout << i << ' ';
    cout << endl;
}

int main () {
    ios::sync_with_stdio (0);cin.tie(0);cout.tie(0);
    int t;
    cin >> t;
    while (t --) {
        solve ();
    }
}


//如果00/11相邻就把他们划分开
//上一个屁股后面如果能接上去就接,否则新开一个

8.19

(2/3,做出第二、三道)
可能对于01串之类的比较敏感

C. Omkar and Baseball

https://codeforces.com/problemset/problem/1372/C
看乱序的有多少段
0段:0
1段:1

大于1段:2(可以通过一些操作变为连续)

#include <bits/stdc++.h>

using namespace std;

void solve () {
    int n, x;
    cin >> n;
    int l = n + 1, r = 0, len = 0;
    for (int i = 1; i <= n; i++) {
        cin >> x;
        if (x != i) {
            len ++;
            l = min (l, i), r = max (r, i);
        }
    }

    if (len == 0)   cout << "0\n";
    else if (len == (r-l+1))    cout << "1\n";
    else    cout << "2\n";
}

int main () {
    int t;
    cin >> t;
    while (t --) {
        solve ();
    }
}

//看乱序的有多少段
//0段:0
//1段:1
//>1段:2(可以通过一些操作变为连续)

C. Binary String Reconstruction

https://codeforces.com/problemset/problem/1400/C
只要保证0的左边第x个和右边第x个都是0即可

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 5;
string s;
int x, n;
int a[N];

void solve () {
    cin >> s >> x;
    n = s.size();
    for (int i = 0; i < n; i++)    a[i] = 1;
    for (int i = 0; i < n; i++) {
        if (s[i] == '0') {
            int st = i - x, ed = i + x;
            //cout << st << ' ' << ed << endl;
            if (st >= 0)    a[st] = 0;
            if (ed < n)     a[ed] = 0;
        }
    }

    for (int i = 0; i < n; i++) {
        bool suc = false;
        if (s[i] == '1') {
            int st = i - x, ed = i + x;
            if (st >= 0 && a[st] == 1)  suc = true;
            if (ed < n && a[ed] == 1)   suc = true;
            if (!suc) {
                cout << "-1\n";
                return ;
            }
        }
    }

    for (int i = 0; i < n; i++)    cout << a[i];
    cout << endl;
}

int main () {
    int t;
    cin >> t;
    while (t --) {
        solve ();
    }
}

//只要保证0的左边第x个和右边第x个都是0即可

F. Binary String Reconstruction

https://codeforces.com/problemset/problem/1352/F
构造规则:s2+1的1串 连接 s0+1的0串 然后 依次补充s1-1个10

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 5;
string s;
int s0, s1, s2;

void solve () {
    cin >> s0 >> s1 >> s2;

    if (s2)     for (int i = 0; i <= s2; i++)   cout << 1;
    if (s0)     for (int i = 0; i <= s0; i++)   cout << 0;
    if (s2 == 0 && s0 == 0) {
        for (int i = 0; i <= s1; i++) {
            if (i & 1)  cout << 1;
            else    cout << 0;
        }
    }   
    else if (s2 == 0) {
        if (s1) {
        //     for (int i = 0; i <= s0; i++)    cout << 0;
        // }
        // else {
            for (int i = 0; i < s1; i++) {
                if (i & 1)  cout << 0;
                else    cout << 1;
            } 
        }       
    }
    else if (s0 == 0) {
        if (s1) {
        //     for (int i = 0; i <= s2; i++)    cout << 1;
        // }
        // else {
            for (int i = 0; i < s1; i++) {
                if (i & 1)  cout << 1;
                else    cout << 0;
            } 
        }       
    }
    else {
        for (int i = 1; i < s1; i++) {
            if (i & 1)  cout << 1;
            else    cout << 0;
        }
    }

    cout << endl;
}

int main () {
    int t;
    cin >> t;
    while (t --) {
        solve ();
    }
}

//构造规则:s2+1的1串 和 s0+1的0串 然后 依次补充s1-1个10

8.20

(1/3,做出第二道)

D. Non-zero Segments

https://codeforces.com/problemset/problem/1426/D
统计前缀和,如果出现过了,就插一个很大的数

#include <bits/stdc++.h>
#define int long long

using namespace std;

signed main () {
    int n, ans = 0, sum = 0;
    cin >> n;
    set<int> s;
    //s.insert (0);
    for (int i = 0; i < n; i++) {
        int x;
        cin >> x;
        sum += x;
        if (s.count (sum) || sum == 0) {
            ans ++;
            sum = x;
            s.clear ();
            //s.insert (0);
        }
        s.insert (sum);
    }
    cout << ans << endl;
}

D2. Sage's Birthday (hard version)

https://codeforces.com/problemset/problem/1419/D2

构造规则:偶数位从小到大填,然后后续的数字再接着从小到大填到奇数位上

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 5;
int a[N], n;

int main () {
    cin >> n;
    for (int i = 1; i <= n; i++)    cin >> a[i];
    if (n <= 2) {
        cout << "0\n";
        for (int i = 1; i <= n; i++)    cout << a[i] << ' ';
        return 0;
    }
    sort (a + 1, a + n + 1);

    vector <int> v(n+1);
    int cnt = 0;
    for (int i = 2; i <= n; i += 2) {
        v[i] = a[++cnt];
    }

    for (int i = 1; i < n; i += 2) {
        v[i] = a[++cnt];
    }

    if (v[n] == 0)  v[n] = a[n];

    cnt = 0;
    for (int i = 2; i < n; i++) {
        if (v[i] < v[i-1] && v[i] < v[i+1])
            cnt ++;
    }
    cout << cnt << endl;
    for (int i = 1; i <= n; i++)    cout << v[i] << ' ';
}


//构造数组使得“相邻左边的和右边的数字都比它大”这样的数字出现的尽可能多

//最多能有(n-1)/2个
//2 4 6 ...填最小,然后填最大

C. Even Picture

https://codeforces.com/problemset/problem/1368/C

可恶的样例。。害得我被误导了。
其实只要按照这样“阶梯型”去构造就很 \(easy\)

#include <bits/stdc++.h>

using namespace std;
int n;
int dx[] = {-1, 0, 1};

int main () {
    cin >> n;
    cout << n * 3 + 4 << endl;
    cout << "0 0\n1 0\n";
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < 3; j++) {
            cout << i + dx[j] << ' ' << i << endl;
        }
    }

    cout << n << ' ' << n + 1 << endl;
    cout << n + 1 << ' ' << n + 1 << endl;

}

//灰格子连通
//每个灰格子都有偶数个邻居
//灰色格子的四面都是灰色格子的数量为n

//阶梯型2-3-3-..-3-2构造即可
//n=几就是几层3

8.21

(0/3,菜死了)

C. Beautiful Sets of Points

https://codeforces.com/problemset/problem/268/C
输出对角线上所有的点就好了,这都没想到!

#include <bits/stdc++.h>

using namespace std;

int main () {
    int n, m;
    cin >> n >> m;
    cout << 1 + min (n, m) << endl;
    for (int i = 0; i <= min (n, m); i++) {
        cout << i << ' ' << min (n, m) - i << endl;
    }
}

//输出对角线上所有的点

C. Ehab and Path-etic MEXs

https://codeforces.com/problemset/problem/1325/C

\(mex(u, v)\) 最大值最小一定是2
链:输出 \(0\) ~ \(n-2\)
树:一定有边不在01的任何公共路径上,标2就行。
实现:找到一个度\(\geq3\)的,填\(0,1,2\)

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 5;
int a[N], b[N], d[N], n;

int main () {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i] >> b[i];
        d[a[i]] ++, d[b[i]] ++;
    }
    int id = 0;
    for (int i = 1; i <= n; i++) {
        if (d[i] >= 3) {
            id = i;
            break;
        }
    }

    if (!id) {
        for (int i = 0; i < n-1; i++) cout << i << endl;
        return 0;
    }

    int k1 = 0, k2 = 3;
    for (int i = 1; i < n; i++) {
        if ((a[i] == id || b[i] == id) && k1 < 3)   cout << k1 ++ << endl;
        else    cout << k2 ++ << endl;
    }
}


//找到一个人度为3的,标01

A. And Matching

https://codeforces.com/problemset/problem/1630/A
cool div1的题

搬搬题解,位运算好难啊

posted @ 2022-08-21 10:56  Sakana~  阅读(148)  评论(0编辑  收藏  举报