1. 程式人生 > 實用技巧 >ICPC(一) - 安徽2019省賽題解(I,J,K)

ICPC(一) - 安徽2019省賽題解(I,J,K)


Teng, Li

2020-05-17

Email: [email protected]


I-你的名字

  • 問題描述

Alice 想要計算他那 N 只貓的名字的價值每隻貓的名字由不超過 1000 個大小寫字母構成,沒有一個名字是空字型串。 Alice有一張*價值字串表”, 上面有 M個代表價值的字串。每個字串由不超過30個大小寫字母構成,同樣不存在空字串。一個貓的名字蘊含多少個價值字串,這個名字就有多少價值,所謂 “蘊含”,是指某個能量字串的所有字元都在名字串中按順序出現 (不一定一個緊接著一個) .
所有的大寫字母和小寫字母都是等價的。比如,在貝黃的名字"Bessie"裡, 蘊含有 “Be” “si” “EE” 以及 “Es” 等等字串,但不蘊含"Ls°或"eB"請幫Alice計算他的貓的名字的價值.

  • 輸入

輸人的第-行是兩個整數 N M
接下來N行,每行一個字串表示貓的名字。
接下來M行,每行一個價值字串
1 <=N<= 1000
1 <= M<=100

  • 輸出

輸出每隻貓蘊含多少個價值字串。

  • 樣例

    • 輸入
    5 3
    Bessie
    Jonathan
    Montgomery
    Alicia
    Angola
    Se  
    nGo  
    oNt
    
    • 輸出
    1
    1
    2
    0
    1
    
  • 解題思路

採用遍歷破解的方法,通過對每一個字串和每一個子串相比較,判斷某一個子串是否為該字串的子串(在這個地方,就需要我們建立一個子串判斷的函式),對於每一個子串進行判斷的過程中需要進行大小寫的轉換處理。

graph LR a[開始] --> b(遍歷每一個字串) --> c(遍歷每一個子串) b --遍歷完畢--> d[結束] c --遍歷完畢, 處理下一個--> b c --為子串--> e((價值+1)) --> c c --不為子串--> f((無操作)) --> c
  • 結果展示

  • 程式碼
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

bool isSubName(string name, string subname) {
    string::iterator i = name.begin(), j = subname.begin();
    while (i != name.end() && j != subname.end()) {
        if (*i > 'A' && *i < 'Z') {
            *i = *i - ('A' - 'a');
        }
        if (*j > 'A' && *j < 'Z') {
            *j = *j - ('A' - 'a');
        }
        if (*i == *j) {
            i++;
            j++;
        } else {
            i++;
        }
    }
    if (j == subname.end()) {
        return true;
    } else {
        return false;
    }
}

void yourname_tmp(int m, int n, string *names, string *subnames) {
    for (int i = 0; i < m; i++) {
        int res = 0;
        for (int j = 0; j < n; j++) {
            if (isSubName(names[i], subnames[j])) {
                res++;
            }
        }
        cout << res << endl;
    }
}

void yourname(void) {
    int m, n;
    cin >> m;
    cin >> n;
    string names[10], subnames[10];
    for (int i = 0; i < m; i++) {
        cin >> names[i];
    }

    for (int j = 0; j < n; j++) {
        cin >> subnames[j];
    }

    yourname_tmp(m, n, names, subnames);
}

int main(void) {
    yourname();
    return 0;
}

J-密信

  • 題目描述

Alice 想給 Bob 發簡訊,簡訊的內容可以看成是一個只有小寫字母的字串 p;為了加密簡訊,Alice 需要只有小寫字母長度為 n 的字串 h ,並且 p 是 h 的子串: Alice 想知道,這樣的字串有多少種。
給出 n 和 M 還有字串 p ,假設一共有 K 種不同的 h ,輸出K mod M

  • 輸入

輸人包含多組資料,第一行是組數 T , T ≤= 50
對於每組測試資料,第一行是 n M
接下來一行是字串 p
n,M <= 10 ^ 12
P 是一個長度不大於 50 且只有小寫字母的字串

  • 輸出

輸出 K mod M

  • 樣例

    • 輸入
    2
    2 100
    ab
    3 100
    ab
    
    • 輸出
    1
    52
    
  • 解題思路

字串,數論思想

  • 結果展示

  • 程式碼
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
 
const int N = 55;
ll n, M;
int len, f[N];
char s[N];
 
void getFail() {
    int j = 0;
    for(int i=1;i<=len-1;i++){
        while (j&&s[j]!=s[i]) j=f[j];
        if (s[j]==s[i]) ++j;
        f[i+1] = j;
    }
}
 
ull qmul(const ull a, const ull b, const ull md) {
	ll c=(ll)a*b-(ll)((ull)((long double)a*b/md)*md);
	return c<0?md+c:((ull)c>md?c-md:c);
}
 
struct Mat {
    ll v[55][55];
    Mat() {memset(v, 0, sizeof v);}
    Mat operator * (const Mat& b) const {
        Mat c;
        for(int k=0;k<=len;k++)
			for(int i=0;i<=len;i++)
				for(int j=0;j<=len;j++){
            c.v[i][j] = (qmul(v[i][k],b.v[k][j],M)+c.v[i][j])%M;
        }
        return c;
    }
    Mat operator ^ (ll nn) {
        Mat b, a=*this;
        for(int i=0;i<=len;i++)
			 b.v[i][i]=1;
        while(nn) {
            if(nn&1LL) b=b*a;
            nn>>=1LL,a=a*a;
        }
        return b;
    }
};
  
int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%lld%lld%s", &n, &M, s);
        len = strlen(s);
        getFail();
        Mat g;
        for(int i=0;i<=len;i++) 
			for(int k='a';k<='z';k++) {
            int nxt = i;
            while (nxt&&s[nxt]!=k) nxt = f[nxt];
            if (s[nxt]==k) ++nxt;
            if (i==len) nxt = len;
            ++g.v[nxt][i];
        }
        g = g^n;
        printf("%lld\n", g.v[len][0]);
    }
}

K-福報

  • 題目描述

員工績效評估對於任何公司都是很重要的,在績效考核中,員工會就最近完成的工作編寫工作反饋。反饋會被遞給他們的上級,然後上級根據收到的反饋來決定績效.
Alice 負責-家知名公司工程部廣]的績效考核系統。該部門遵循樹形結構。每位員工都有一個直接上級,最上級是部門總監.
讓上級評估其直接下屬的表現並不是很有效.經過深人研究,Alice 想出了一個新的績效考核系統,主要思路是在現有的公司結構中補充每個員工的技術等級,新的績效評估流程如下,員工要準備他們的工作反饋,然後向所有比他技術等級高的上級(直接上級和間接上級)遞交工作反饋;上級需要花時間稽核所有遞交給他的工作反饋。
Alice 對這個新系統感到非常滿意,但她不確定這在實踐中是否可行,她想知道每個員工稽核下屬工作反饋所需的時間,你能幫她嗎?

  • 輸入

輸人的第一行是整數 E , 員工的總數。接下來有 E 行,第 i 行有三個整數mi,ri ,ti表示第 i 號員工對應的上級編號,他的技術等級,稽核他的工作反饋所需要的時間,部門總監沒有上級,所以他的上級編號是 -1
1 < E, mi, ri,ti < 10^6

  • 輸出

按編號順序輸出每位員工稽核下屬工作反饋所需時間

  • 樣例

    • 輸入
    5
    4 4 80
    1 1 40
    -1 10 60
    3 5 50
    4 8 70
    
    • 輸出
    40
    0
    240
    120
    0
    
  • 解題思路

基於棧的思想,遍歷每一個元素。

將當前元素的上級入棧,如此往復,知道不滿足條件,停止入棧。

從棧頂開始出棧直到只有一個元素,出棧元素對應時間加上棧底元素對應的時間。

遍歷完成,輸出結果。

graph LR a[開始] --> b(遍歷每一個元素) b --1.尋找上級-->c((入棧))--不滿足入棧條件-->e(入棧結束) b --2.遍歷棧,符合比棧底等級高條件者,時間計數器增加--> f((出棧))--只有棧底-->g(出棧結束) b --遍歷完畢,輸出結果--> d[結束]
  • 結果展示

  • 程式碼
#include <iostream>
#include <stack>
#include <vector>
#include <algorithm>
using namespace std;

typedef struct employee
{
    int no_, id, lv, tm;
}Eple;

Eple epleCons(int no_, int id, int lv, int tm) {
    Eple eple;
    eple.no_ = no_;
    eple.id = id;
    eple.lv = lv;
    eple.tm = tm;
    return eple;
}

void nineNineSix () {
    int N;
    cin >> N;
    vector<Eple> eples;
    int id, lv, tm;
    for (int i = 0; i < N; i++) {
        cin >> id >> lv >> tm;
        eples.push_back(epleCons(i + 1, id, lv, tm));
    }
    int T[N]; // 記錄時間
    for (int i = 0; i < N; i++) {
        T[i] = 0;
    }
    for (int i = 0; i < N; i++) {
        stack<Eple> S;
        S.push(eples[i]);
        int btmTime = S.top().tm; // 棧底時間
        int btmLv = S.top().lv; // 棧底級別
        while (S.top().id != -1) {
            // 只要不是最高級別,一直入棧
            S.push(eples[S.top().id - 1]);
        }
        while (S.size() != 1) {
            // 將除了棧底元素所有出棧
            if (S.top().lv > btmLv) {
                // 時間累加
                T[S.top().no_ - 1] += btmTime;
            }
            S.pop();
        }
        S.pop(); // 棧底出棧
    }
    for (int i = 0; i < N; i++) {
        cout << T[i] << endl;
    }
}

int main() {
    nineNineSix();
    return 0;
}