暑 假 隊 測 Round #5
阿新 • • 發佈:2020-08-16
\(30+80+30=140pts\)
最菜的一次,題目不難,但打的全是暴力。
T2資料過水,假貪心騙了80分。
T1:字串模擬
假使我們找到一個"agnus",
其左端點是\(l\),其右端點是\(r\).(\(1\le l \le r \le n\) )
那麼很顯然包含它的子串\(x\) ~ \(y\)只需要滿足\(x \le l ~\)&&\(~ r \le y\)。
總數量就是\(l \times (n-r+1)\).
避免重複統計,我們需要記錄上一個"agnus"的結束位置\(pre\)
統計答案時應是\(ans\)
\(Code\):
#include<bits/stdc++.h> using namespace std; string st,s="agnus"; int n,ans,pr; int main(){ cin>>st; n=st.size(); for(int i=0;i<n;i++) if(st.substr(i,5)==s)ans+=(i+1-pr)*(n-i-4),pr=i+1; printf("%d\n",ans); return 0; }
T2:單調佇列
一眼會想到貪心求解,
思路很簡單,使得當前溫度儘可能的低.
溫度不夠就降下去重新升溫,升溫儘可能少
但是會被下面這組資料卡掉:
9
3 3
1 3
1 1
2 2
3 3
4 5
4 5
3 5
3 3
我們要做的其實是維護一段連續的子段。
使得其中的溫度單調不降。
單調佇列可以輕鬆解決。
\(Code:\)
#include<bits/stdc++.h> using namespace std; const int N=1e6+10; int n,a[N],b[N],q[N],ans; int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d %d",&a[i],&b[i]); int l=1,r=0; for(int i=1;i<=n;i++){ while(l<=r&&a[i]>a[q[r]])r--; q[++r]=i; while(l<=r&&b[i]<a[q[l]])l++; ans=max(ans,i-q[l-1]); } printf("%d\n",ans); return 0; }
T3:揹包
01揹包的轉移方程是 \(f[i][j]=f[i-1][j]+f[i-1][j-a[i]]\)
我們可以先做揹包求出所有的\(f[i][j]\),
移項:\(f[i-1][j-a[i]]=f[i][j]-f[i-1][j]\);
所以當\(f[i][j]-f[i-1][j]==0\)時此硬幣對\(j\)元錢的組成沒有貢獻。
\(Code:\)
#include<bits/stdc++.h>
using namespace std;
const int N=3e5,M=105;
int ans,a[M],f[N+5];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
f[0]=1;
for(int i=1;i<=n;i++)
for(int j=N;j>=0;j--)
if(f[j]&&j+a[i]<=N)f[j+a[i]]+=f[j];
for(int i=1;i<=n;i++){
ans=0;
for(int j=0;j<=N;j++)
if(f[j]&&j+a[i]<=N)f[j+a[i]]-=f[j];
for(int j=1;j<=N;j++)if(f[j])ans++;
for(int j=N;j>=0;j--)
if(f[j]&&j+a[i]<=N)f[j+a[i]]+=f[j];
printf("%d\n",ans);
}
return 0;
}