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
-
解題思路
採用遍歷破解的方法,通過對每一個字串和每一個子串相比較,判斷某一個子串是否為該字串的子串(在這個地方,就需要我們建立一個子串判斷的函式),對於每一個子串進行判斷的過程中需要進行大小寫的轉換處理。
- 結果展示
- 程式碼
#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;
}