1. 程式人生 > 實用技巧 >C語言有引數巨集定義與無引數巨集定義

C語言有引數巨集定義與無引數巨集定義

目錄

A. Special Permutation

題意:

給出n,要求輸出一個1到n的全排列,需要滿足\(a_i\not=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\n", t);
        else 
        {
            for (int i = 1; i <= sum - 1; ++i) printf("%lld ", res_val);
            printf("%lld\n", (t / qmi(res_val, sum - 1)));
        }
        
    }
    return 0;
}

E. Number of Simple Paths

大意:

給出一個n個點n條邊的無向圖,問從任意一個點走到其他任意一個點,有多少路徑,需要注意的是1->2->3與3->2->1視為相同的路徑

思路:

n個點n條邊的無向圖,被稱為基環圖,它可以看做一個基環再向外延伸出幾個樹的結構,如下圖:

對於同一個樹上的兩個點,只有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\n");
                        int x = min(maxr[st]-1, mid-1);
                        int y = max(mid + 1, maxl[en]+1);
                        printf("%d %d %d\n", x, y - x - 1, n - y + 1);
                        break;
                    }
                }
            }
            if(flag==0)
                no[a[i]] = 1;
        }
        if(flag==0){
            printf("NO\n");
        }
    }
    return 0;
}