apcs特訓
P2
重點:每次遷移時另外開一個陣列,算完再覆蓋到原陣列
重點:可以記每一橫列填到右邊的哪裡

5
5
5
3
3每次遇到小寫大寫交換時,判斷先前連續長度是>k, =k, 或<k
#include <bits/stdc++.h>
#define NL "\n"
#define LL long long
using namespace std;
int main(){
ios_base::sync_with_stdio(false);
cin.tie(0);
int k;
cin>>k;
string str;
cin>>str;
bool prev=isupper(str[0]);
LL len=1, cur=0, ans=0;
for(int i=1;i<(int)str.size();++i){
bool tmp=isupper(str[i]);
if(tmp==prev) len++;
else{
if(len==k){
cur+=k;
ans=max(ans, cur);
}
else if(len>k){
ans=max(ans, cur+k);
cur=k;
}
else{
cur=0;
}
len=1;
}
prev=tmp;
//cout << i << ": " << ans << NL;
}
if(len>=k){
cur+=k;
ans=max(ans, cur);
}
cout << ans << NL;
}其他:
https://zerojudge.tw/ShowProblem?problemid=i400
https://zerojudge.tw/ShowProblem?problemid=f580
P3
智障解:套資節直接做(sparse table或線段樹)
聰明解:前墜和+ 對原序列排序,如果最小值不再區間就pop
把每個團隊組成用位元表示(ex: 第0為=1代表有a),放進map
#include <bits/stdc++.h>
using namespace std;
typedef pair<long long,long long> pll;
typedef pair<int,int> pii;
typedef long long ll;
int main(){
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int m, n;
cin>>m>>n;
map<ll,ll> save;
ll ans=0;
for(int i=0;i<n;++i){
ll x=0;
string s;
cin>>s;
for(auto a:s) x|=(1<<(a-'A')); //convert it into bit
// calculate reverse bit
ll rev=0;
for(int j=0;j<m;++j) if((x&(1<<j))==0) rev|=(1<<j);
ans+=save[rev];
save[x]++;
}
cout<<ans<<"\n";
}
作法:掃描線,排序,etc.
差分
dp[i][j]:在(i,j)的最大值
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j)
dp[i][j]=max(grid[i][j]+dp[i-1][j], grid[i][j]+dp[i][j-1]);
for(int j=m;j>=1;--j){
// go from right to left
l[j]=max(dp[i-1][j]+grid[i][j], l[j+1]+grid[i][j]);
dp[i][j]=max(dp[i][j], l[j]);
}
}
觀察:
- 任兩字串皆不同(題目條件),所以如果會形成聖筊長度一定不一樣,因此枚舉較長的那個不會算到重覆的
- 固定較長的一半後,要找的其實就是所有共同前後綴,在用map找是否有中間那段可以接
P4
記得最長連續和?
for(int i=1;i<=m;++i) for(int j=1;j<=n;++j){
dp[i][j]=max(0ll, dp[i-1][j-1])+a[i]*b[j];
ans=max(ans, dp[i][j]);
}想想看對答案二分搜(回想基地台)
高度越低越有可能塞更多海報
apcs特訓
By alan lai
apcs特訓
- 236