\(140pts, Rank24\)
題目列表:
- 簡單的序列
- 簡單的字串
- 簡單的
- 困難的圖論
簡單的序列
\(100pts\)
題意:
gtm1514 不喜歡序列。但是一天他拿到了一個序列。
這個序列非常雜亂,於是 gtm1514 想要整理一下這個序列。但是由於他非常的菜,他只會進行一個操作:選擇一個 \(ai\),把它變成 \(⌊\frac{a_i}2⌋\)。
gtm1514 又菜又愛擺,他想讓你找到使得數列嚴格遞增的最小操作次數。如果無解,輸出 −1。
對於 100% 的資料,\(t≤10^4,n≤30,a_i≤2×10^9\)。
正解:
直接暴力即可,實際複雜度 \(O(t\ n \log_{2}{a_i})\)
將 \(i\) 從 \(n\) 到 1 遍歷,每當遇到一個 \(i\) 使得 $a_i>=a_{i+1} $, 不斷計算 $a_i= \lfloor {\frac{a_i}2} \rfloor $,直到 \(a_i<a_{i+1}\)。
code:
#include<bits/stdc++.h>
using namespace std;
const int N = 50;
int T, n, a[N];
int work(int &now, int ne){
int cnt = 0;
while(now >= ne){now /= 2, cnt++;}
return cnt;
}
int main(){
// freopen("in.in", "r", stdin); freopen("out.out", "w", stdout);
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%d", &a[i]);
}
int ans = 0;
for(int i=n-1; i>=1; i--){
ans += work(a[i], a[i+1]);
if(i != 1 and a[i] == 0){
ans = -1;
break;
}
}
printf("%d\n", ans);
}
return 0;
}
簡單的字串
\(30 pts\),最唐的一次掛分
題意:
現在有一個字串,但是它長得還是十分甚至九分混亂邪惡。gtm1514 想要整理一下這個字串。
他發明了一個神奇的操作:一次操作使得字串縮短一位,新字串的第 i 位可以與原串的第 i 或 i+1 位相同。
他想知道最少經過多少次操作可以使整個字串全相同,即只有一種字母。
賽時分析:
一眼有點感覺,可做。於是想想想,假假假。手模了半個小時之後不知道怎麼著就想到正解了,突然就跳出來了。結果打完很開心地以為能 \(A\) 兩個題了,結果 map 陣列範圍開錯了......
正解:
每個英文字母的擴充套件的次數其實是它到與自己相同的字母的上一個位置的距離。
求出原每個位置上的前驅,然後列舉 26 個英文字母的所有位置,對於每一種英文字母,滿足條件所需即為所有位置到前驅距離以及最後一個位置到原序列最後一個字母的距離的最大值,答案就是 26 個字母的所需的最小值。
code:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int n;
char s[N];
// map<char, int>la;
int cnt[130][N], la[200];
int work(char c){
int num = n - la[c];
for(int i=1; i<=cnt[c][0]; i++){
num = max(num, cnt[c][i] - cnt[c][i-1] - 1);
}
return num;
}
int main(){
// freopen("in.in", "r", stdin); freopen("out.out", "w", stdout);
cin>>(s+1);
n = strlen(s+1);
for(int i=1; i<=n; i++){
// pre[i] = la[s[i]];
la[s[i]] = i;
cnt[s[i]][++cnt[s[i]][0]] = i;
}
int ans = N;
for(char c='a'; c<='z'; c++){
if(!cnt[c][0]) continue;
ans = min(ans, work(c));
}
printf("%d", ans);
return 0;
}