B.Crazy Binary String
題目
給定一個長度爲n的只包含0和1的字符串。
要求0和1個數相等的最長的子序列和子串。
題解
子序列很簡單,統計全部的0和1的個數,它們兩者中的較小值×2即爲答案。
子串需要用sum數組記錄。其中sum[i]表示1~i中0和1數量的差值,如果存在sum[i]=sum[j],那麼從i到j的0和1數量必然相等。
所以,問題就轉化成了求sum數組中兩個相等元素的最長距離。
由於比賽時數組從0開始存,導致用map標記時對於第一個位置的元素出現了問題。
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 200005;
template <class T>
void read(T &x) {
T f=1;x=0;char s=getchar();
while(s<'0'||s>'9') {if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
x *= f;
}
int n,a[maxn],cnt1,cnt2,ans,res,b[maxn],sum[maxn];
map<int,int> mp;
string s;
int main() {
read(n);
cin >> s;
if(s[0]=='0') a[0]=1,b[0]=0;
else a[0]=0,b[0]=1;
for(int i=0;i<n;i++) {
if(s[i]=='0') cnt1++;
else cnt2++;
if(s[i]=='0' && i>0) a[i] = a[i-1]+1,b[i]=b[i-1];
else if(i>0) a[i] = a[i-1], b[i] = b[i-1]+1;
sum[i] = a[i] - b[i];
if(sum[i]==0) ans = max(ans,i+1);
}
for(int i=0;i<n;i++) mp[sum[i]]=-1;
for(int i=0;i<n;i++) {
if(mp[sum[i]]==-1) mp[sum[i]] = i;
else ans = max(ans,i-mp[sum[i]]);
}
res = min(cnt1,cnt2)*2;
cout << ans << ' ' << res << endl;
return 0;
}
F. Planting Trees
題目
在n×n的矩陣裏,求出一個最大的矩形,使得該矩形中元素的 最大值-最小值≤m 。
其中 。
題解
題目中已經說明了要用的做法。
首先枚舉上下邊界u和d,維護ma[i]和mi[i]。
其中ma[i]表示從a[u][i]到a[d][i]的最大值,mi[i]就是這個區間的最小值。
已經得到同一列的最大最小值以後,可以再去維護左右邊界。
用r去表示右邊界從1往n掃,再用兩個單調隊列維護當前左右邊界中的ma[i]的最大值和mi[i]的最小值(因爲只看這個矩形內的最大最小值)。
如果,那麼更新ans;
否則將左區間向右移動,並且更新兩個單調隊列。
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 505;
template <class T>
void read(T &x) {
T f=1;x=0;char s=getchar();
while(s<'0'||s>'9') {if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
x *= f;
}
int t,n,m,a[maxn][maxn],mi[maxn],ma[maxn];
int main() {
read(t);
while(t--) {
read(n), read(m);
int ans = 0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
read(a[i][j]);
for(int d=1;d<=n;d++) {
for(int i=1;i<=n;i++) ma[i]=mi[i]=a[d][i];
for(int u=d;u<=n;u++) {
int len = u-d+1;
for(int i=1;i<=n;i++) {
ma[i] = max(ma[i],a[u][i]);
mi[i] = min(mi[i],a[u][i]);
}
deque<int> p,q;
p.clear(), q.clear();
int l = 1;
for(int i=1;i<=n;i++) {
while(!p.empty() && ma[p.back()]<=ma[i]) p.pop_back(); //維護最大
p.push_back(i);
while(!q.empty() && mi[q.back()]>=mi[i]) q.pop_back(); //維護最小
q.push_back(i);
if(!p.empty()&&!q.empty()) {
int maxi = p.front();
int mini = q.front();
if(ma[maxi]-mi[mini]<=m) {
ans = max(ans,(i-l+1)*len);
} else {
while(!p.empty() && !q.empty() && ma[p.front()]-mi[q.front()]>m) {
++l;
if(p.front()<l) p.pop_front();
if(q.front()<l) q.pop_front();
}
}
}
}
}
}
cout << ans << endl;
}
return 0;
}
H. Magic Line
題目
在平面上有n個點,畫一條線將平面分成兩部分,使得兩部分的點個數一樣多。
其中
題解
毒瘤題卡精度。
將點按橫縱座標排個序,然後對於中間兩個點,如果可以豎直着劃線就豎直着畫,否則就稍微傾斜一點。
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 200005;
template <class T>
void read(T &x) {
T f=1;x=0;char s=getchar();
while(s<'0'||s>'9') {if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
x *= f;
}
int t,n,a1,a2,b1,b2;
struct node{
int x,y;
bool operator<(const node &b)const {
if(x==b.x) return y<b.y;
return x<b.x;
}
}e[maxn];
int main() {
read(t);
while(t--) {
read(n);
for(int i=0;i<n;i++) read(e[i].x), read(e[i].y);
sort(e,e+n);
int k = n/2 - 1;
if(e[k+1].x-e[k].x>1) {
a1 = a2 = e[k].x+1;
b1 = 0;
b2 = 1;
} else {
a1 = e[k].x-1;
b1 = e[k].y+999000000+1;
a2 = e[k].x+1;
b2 = e[k].y-999000001+1;
}
cout << a1 << ' ' << b1 << ' ' << a2 << ' ' << b2 << endl;
}
return 0;
}
J. LRU management
本題要求實現一個可以按照序號查找的雙向循環鏈表,即可以完成增刪查改。本題內容篇幅較大,會在另一篇文章中詳細介紹。
傳送門:https://blog.csdn.net/zxwsbg/article/details/97496860