Codeforces Round #686 (Div. 3)

A. Special Permutation

题意:

给出n,要求输出一个1到n的全排列,需要满足(a_i ot=i)

思路:

直接输出2到n,最后输出1即可

#include<bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;
int t,n;
int main(){
    cin>>t;
    while(t--){
        cin >> n;
        for(int i=2;i<=n;i++){
            cout<<i<<' ';
        }
        cout << 1;
        cout<<endl;
    }
    return 0;
}

B. Unique Bid Auction

题意:

给出一个数组,要求输出所有只出现过一次的数中最小的数

思路:

直接求即可

#include<bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;
int t, n,a[N];
int main(){
    cin >> t;
    while(t--){
        cin>>n;
        map<int, int> mp;
        for (int i = 1; i <= n;i++){
            cin >> a[i];
            mp[a[i]]++;
        }
        int res = 0x3f3f3f3f;
        int pos = 0;
        for (int i = 1; i <= n;i++){
            if(mp[a[i]]==1){
                if(res>a[i]){
                    res = a[i];
                    pos = i;
                }
            }
        }
        if(res==0x3f3f3f3f){
            cout << -1 << endl;
        }
        else{
            cout << pos << endl;
        }
    }
    return 0;
}

C. Sequence Transformation

题意:

给出一个数组,只能选择一个数字x,然后每次都要消一个[L,R],[L,R]中不能包含x

问使得数列全相等的最少操作数

思路:

模拟题,读入的时候直接判断(a_i)(a_{i-1})是否相同以及是否是第一次出现,然后将对应的答案加一即可

#include<bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;
int t,n,a[N];

int main(){
    cin>>t;
    while(t--){
        cin>>n;
        map<int ,int >mp;
        for(int i=1;i<=n;i++){
            cin>>a[i];
            if(i!=1){
                if(a[i]!=a[i-1]){
                    if(mp[a[i]]==0)
                    mp[a[i]]++;
                    mp[a[i - 1]]++;
                }
            }
        }
        int res=0x3f3f3f3f;
        for(int i=1;i<=n;i++){
            res=min(res,mp[a[i]]);
        }
        cout<<res<<endl;
    }
    return 0;
}

D. Number into Sequence

题意:

给出n,要求输出最长的一组数,满足它们的乘积能被n整除。而且(a_i)能够整除(a_{i-1})

思路:

质因子分解,找出出现次数x最多的质因子,先输出前x-1个,最后乘上其他因数的乘积输出。

#include <bits/stdc++.h>

using namespace std;

int const N = 1e7 + 10;
int n, m, T;
int prime[N], cnt;
int st[N];
long long sum = 0, res_val = 0,t,x;

void get_prime(int n) {
    for (int i = 2; i <= n; ++i) {
        if (!st[i]) prime[cnt++] = i; // 如果这个数字没有被记录,那么这个数字必然为素数,记录一下
        for (int j = 0; prime[j] <= n/i; ++j) {
            st[prime[j] * i] = true;  // 筛掉pj*i这个合数
            if (i % prime[j] == 0)  break; // i%pj==0,说明pj是i的最小素因子,因此i*素数的最小素因子也是pj,在i递增的时候也会被筛掉,因此不需要在这里判断
        }                
    }
}

long long  qmi(long long a, long long k) {
    long long res = 1 ;  // res记录答案, 模上p是为了防止k为0,p为1的特殊情况
    while(k) {  // 只要还有剩下位数
        if (k & 1) res = (long long)res * a ;  // 判断最后一位是否为1,如果为1就乘上a,模上p, 乘法时可能爆int,所以变成long long
        k >>= 1;  // 右移一位
        a = (long long) a * a ;  // 当前a等于上一次的a平方,取模,平方时可能爆int,所以变成long long
    }
    return res;
}


int main() {
    get_prime(N - 1);
    cin >> T;
    while(T--) {
        scanf("%lld", &x);
        t = x;
        sum = 0, res_val = 0;
        for (int i = 0; prime[i] <= x / prime[i]; ++i) {
            int p = prime[i];
            if (x % p == 0) {
                int s = 0;
                while (x % p == 0) {
                    s++;
                    x /= p;
                }
                if ((long long)s > sum) {
                    sum = (long long)s;
                    res_val = p;
                }
            }
        }
        if (x > 1) {
            if ((long long)1 > sum) {
                sum = 1;
                res_val = x;
            }
        }
        cout << sum << endl;
        if (sum == 1) 
        printf("%lld
", t);
        else 
        {
            for (int i = 1; i <= sum - 1; ++i) printf("%lld ", res_val);
            printf("%lld
", (t / qmi(res_val, sum - 1)));
        }
        
    }
    return 0;
}

E. Number of Simple Paths

大意:

给出一个n个点n条边的无向图,问从任意一个点走到其他任意一个点,有多少路径,需要注意的是1->2->3与3->2->1视为相同的路径

思路:

n个点n条边的无向图,被称为基环图,它可以看做一个基环再向外延伸出几个树的结构,如下图:

DhwzuV.png

对于同一个树上的两个点,只有1条路径,所以每个树提供了(C_{num}^{2})个路径(num为这棵树的节点数),而对于不在同一个树上的两个点,因为需要经过基环,所以就存在从两种经过环的方式,所以为2条路径,所以我们可以先按照每对点都有2条路径来做,然后删掉每棵树提供的路径即可。

怎么找环呢?利用拓扑排序,没有被遍历到的节点就一定在环上。最后再对环上的每个节点(即每棵树的根节点)进行一遍dfs找出这棵树的节点数即可

#include<bits/stdc++.h>

using namespace std;

const int N = 2e5 + 5;
typedef long long LL;
int t, n,du[N],istree[N],num[N];
vector<int> mp[N];

void dfs1(int now,int fa){
    for (int i = 0; i < mp[now].size();i++){
        int next = mp[now][i];
        if(next==fa){
            continue;
        }
        du[next]--;
        du[now]--;
        if(du[next]==1){
            istree[next] = 1;
            dfs1(next, now);
        }
    }
}

int dfs2(int now,int fa){
    num[now] = 1;
    for (int i = 0; i < mp[now].size();i++){
        int next = mp[now][i];
        if(next==fa)
            continue;
        if(istree[next]){
            num[now] += dfs2(next, now);
        }
    }
    return num[now];
}

int main(){
    cin >> t;
    while(t--){
        cin >> n;
        for (int i = 1; i <= n;i++){
            mp[i].clear();
            istree[i] = 0;
            du[i] = 0;
        }
        for (int i = 1; i <= n ;i++){
            int x, y;
            cin >> x >> y;
            mp[x].push_back(y);
            mp[y].push_back(x);
            du[x]++;
            du[y]++;
        }
        for (int i = 1; i <= n;i++){
            if(du[i]==1){
                istree[i] = 1;
                dfs1(i,0);   //找环
            }
        }
        LL res = n * ((LL)n - 1);
        for (int i = 1; i <= n;i++){
            if(istree[i]==0){
                dfs2(i, 0);   //找树
                res-=num[i] * ((LL)num[i]  - 1)/2;
            }
        }
        cout << res << endl;
    }
    return 0;
}

F. Array Partition

大意:

给出一个数组,要求将这个数组分成长度分别为x,y,z(均不为0)的三部分,使得中间一部分的数组最小值等于前后两部分数组的最大值,即:(max(1, x) = min(x + 1, x + y) = max(x + y + 1, n))

思路:

首先单调栈维护每个位置上的数所控制的左右端点,直接找出现次数大于等于3的数,然后判断这个数第一次出现的位置能否控制到最左边,最后出现的位置能否控制最右边,如果能就枚举中间出现的位置,看控制的区间是否有交集即可

#include<bits/stdc++.h>

using namespace std;

const int N = 2e5 + 5;
typedef long long LL;
int t, n,a[N],maxl[N],maxr[N],minl[N],minr[N];
int main(){
    cin >> t;
    while(t--){
        cin >> n;
        stack<int> st;
        for (int i = 1; i <= n;i++){
            scanf("%d", &a[i]);
        }
        for (int i = 1; i <= n;i++){
            while(!st.empty()&&a[st.top()]>=a[i]){   //求以a[i]为最小值的左区间
                st.pop();
            }
            if(st.empty()){
                minl[i] = 0;
            }
            else{
                minl[i] = st.top();
            }
            st.push(i);
        }
        while(!st.empty()){
            st.pop();
        }
        for (int i = n; i >= 1;i--){
            while(!st.empty()&&a[st.top()]>=a[i]){   //求以a[i]为最小值的右区间
                st.pop();
            }
            if(st.empty()){
                minr[i] = n+1;
            }
            else{
                minr[i] = st.top();
            }
            st.push(i);
        }
        while(!st.empty()){
            st.pop();
        }
        for (int i = 1; i <= n;i++){
            while(!st.empty()&&a[st.top()]<=a[i]){   //求以a[i]为最大值的左区间
                st.pop();
            }
            if(st.empty()){
                maxl[i] = 0;
            }
            else{
                maxl[i] = st.top();
            }
            st.push(i);
        }
        while(!st.empty()){
            st.pop();
        }
        for (int i = n; i >= 1;i--){
            while(!st.empty()&&a[st.top()]<=a[i]){   //求以a[i]为最大值的右区间
                st.pop();
            }
            if(st.empty()){
                maxr[i] = n+1;
            }
            else{
                maxr[i] = st.top();
            }
            st.push(i);
        }
        unordered_map<int, vector<int> > mp;
        unordered_map<int, int> no;
        for (int i = 1; i <= n;i++){
            mp[a[i]].push_back(i);
            no[a[i]] = 0;
        }
        int flag = 0;
        for (int i = 1; i <= n;i++){
            if(flag)
                break;
            if(mp[a[i]].size()<3){
                continue;
            }
            if(no[a[i]]==1){
                continue;
            }
            int st = mp[a[i]][0], en = mp[a[i]][mp[a[i]].size()-1];
            if(maxl[st]==0&&maxr[en]==n+1){
                for (int j = 1; j < mp[a[i]].size() - 1;j++){
                    int mid = mp[a[i]][j];
                    
                    if(minl[mid]+1<=maxr[st]&&minr[mid]-1>=maxl[en]){
                        flag = 1;
                        printf("YES
");
                        int x = min(maxr[st]-1, mid-1);
                        int y = max(mid + 1, maxl[en]+1);
                        printf("%d %d %d
", x, y - x - 1, n - y + 1);
                        break;
                    }
                }
            }
            if(flag==0)
                no[a[i]] = 1;
        }
        if(flag==0){
            printf("NO
");
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/14072003.html