牛客小白月賽101 A~E
A-tb的區間問題
題意:tb 給了 fc 一個長度為 n 的陣列 A, fc 對 A 進行 k 次如下操作:
刪除陣列第一個元素或者刪除陣列最後一個元素。
求最後得到的陣列和的最大值。
思路:最後刪除的是某一組前字尾,一一去列舉可行的區間即可。
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
ll a[N],s[N];
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
int n,k; cin>>n>>k;
for(int i = 1;i <= n; i++)
cin>>a[i];
for(int i = 1;i <= n; i++)
s[i] = s[i-1] + a[i];
int len = n-k;
ll ans = 0;
for(int i = 1;i <= n; i++)
{
if(i-len+1 >= 1){
ans = max(ans,s[i]-s[i-len]);
}
}
cout<<ans<<"\n";
return 0;
}
B-tb的字串問題
題意:tb 給了 fc 一個字串。
fc 對字串可以進行若干次 (可能是0) 次如下操作:
選擇子串 ''fc'' 或者子串 ''tb'' ,將其從字串中刪去。
求最後剩下字串的最短長度。
子串:原字串中下標連續的一段字串。
思路:能刪我們肯定刪呀,而且"fc"和"tb"也沒有共同字母也沒有干擾。我們可以用棧去維護,類似括號匹配那種。
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
int n; cin>>n;
string s; cin>>s;
s = "?" + s;
stack<char>st;
for(int i = 1;i <= n; i++)
{
if(st.size() > 0){
char x = st.top();
char now = s[i];
if((x=='f'&&now=='c')||(x=='t'&&now=='b'))
st.pop();
else st.push(now);
}else st.push(s[i]);
}
cout<<st.size()<<"\n";
return 0;
}
/*
12
tfffffcccccb
*/
C-tb的路徑問題
題意:tb 給了 fc 一張有 \(n \times n\)個格點的圖。 圖上每個格點都寫著一個數。第 \(i\) 行第\(j\)列的格點上寫著的數字為 \(i\) 和 \(j\)的最大公約數。 現在 fc 需要從第 1行第 1 列出發,去往第 n 行第 n 列處的格點,fc 可以消耗一點能量移向相鄰的格點。 在任何時,設 fc 所位於的格點上所寫的數字為 x ,如果 x 不為 1 ,他可以使用傳送陣傳送到任何數字為 x 的格點,此操作不消耗能量。求 fc 到達第 n行第 n列所消耗的最少能量。
相鄰:如果用 (x,y) 表示第 x行第 y 列的位置,(x,y) 與 (x+1,y),(x,y+1),(x−1,y),(x,y−1)(x+1,y) 相鄰。
思路:我們發現對角線的數字都是每個數字第一次出現的位置,就算要瞬移也要先到這裡。那麼我們考慮列舉先到哪個數字,然後瞬移到距離(n,n)最近的地方,再一步步走即可。
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
int n; cin>>n;
ll ans = (n-1)*2;
for(int i = 2;i <= n; i++)
{
int x = i,y = i;
x = n/i*i;
y = (x-1)/i*i;
ll t = (i-1)*2;
if(y > 0)
t += (n-x)+(n-y);
else t += (n-i)*2;
ans = min(ans,t);
// cout<<"x = "<<x<<" y = "<<y<<" t = "<<t<<"\n";
}
cout<<ans<<"\n";
return 0;
}
D-tb的平方問題
題意:tb 給了 fc 一個陣列 A 。
隨後, tb 對 fc 進行了 q 次詢問,每次詢問 tb 給 fc 一個 x,需要 fc 給出包含了 x 位置且區間和為完全平方數的連續子陣列個數。
完全平方數:存在正整數 t ,滿足\(t \times t = x\) ,則稱 x 為完全平方數
連續子陣列:原陣列中某段下標連續的元素按原順序構成的陣列。
思路:可以先求個字首和,然後列舉區間,如果是完全平方數那麼這段區間的貢獻加1。對於區間加很容易想到差分。
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 3100;
int s[N],d[N],a[N];
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
int n,q; cin>>n>>q;
for(int i = 1;i <= n; i++){
cin>>a[i];
s[i] = s[i-1] + a[i];
}
for(int i = 1;i <= n; i++)
{
for(int j = i;j <= n; j++)
{
int l = i,r = j;
int t = s[r]-s[l-1];
int tt = sqrt(t);
if(tt*tt == t)
d[l]+=1,d[r+1]-=1;
}
}
for(int i = 1;i <= n;i++)
d[i]+=d[i-1];
while(q--)
{
int x; cin>>x;
cout<<d[x]<<"\n";
}
return 0;
}
E-tb的數數問題(調和級數)
題意:tb 給了 fc 一個包含若干個數字的可重集合 A ,如果我們說一個數字 x 是好的當且僅當 \(\forall \ d | x\) ,有 \(d \in A\)。
現在,fc 想知道有多少個不同的正整數是好的,請你告訴他吧。
d∣x : 表示 d 為 x 的約數。
\(\forall \ d | x\) ,有 \(d \in A\) : x 的任何約數都至少在 A 中出現一次。
思路:最後的好數一定是A裡面的數(因為至少包含數本身)。g[x]=1表示x存在。我們正常的求f[x]的約數有幾個,h[x]是在A裡面的x的約數個數。如果f[x]==h[x]則說明都在了。這裡是調和級數的複雜度\(O(n\log{n})\)(類似於 Eratosthenes 篩的思路)。
int d[1000001] = {0}; // 儲存因數倍數,初始全為 0
for (int i = 1; i <= n; i++) // 列舉 [1, n] 的數
{
for (int j = i; j <= n; j += i) // 列舉 i 的倍數
{
d[j]++;
}
}
程式碼:
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e6 + 10;
ll a[N],f[N],g[N],h[N];
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
int n; cin>>n;
ll mx = 0;
for(int i = 1;i <= n; i++)
{
cin>>a[i];
mx = max(mx,a[i]);
g[a[i]] = 1;
}
for(int i = 1;i <= mx; i++)
{
for(int j = i;j <= mx; j += i){
f[j]++;
h[j] += g[i];
}
}
ll ans = 0;
for(int i = 1;i <= mx; i++)
ans += (f[i] == h[i]);
cout<<ans<<"\n";
return 0;
}