[編程題]壓縮算法
時間限制:C/C++ 2秒,其他語言4秒
空間限制:C/C++ 256M,其他語言512M
小Q想要給他的朋友發送一個神祕字符串,但是他發現字符串的過於長了,於是小Q發明了一種壓縮算法對字符串中重複的部分進行了壓縮,對於字符串中連續的m個相同字符串S將會壓縮爲[m|S](m爲一個整數且1<=m<=100),例如字符串ABCABCABC將會被壓縮爲[3|ABC],現在小Q的同學收到了小Q發送過來的字符串,你能幫助他進行解壓縮麼?
思路:
大模擬,遞歸的將所有[]區間的內容暴力轉換就好了,不得不說這個題放第一個比較折磨人
#include <bits/stdc++.h>
using namespace std;
string str;
const int maxn=1e5+10;
int match[maxn];
int getint(string s){
int len=s.size();
int ans=0;
for(int i=0;i<len;i++){
ans+=(s[i]-'0')*pow(10,len-i-1);
}
return ans;
}
//得到l,r這個區間的串
string solve(int l,int r){
string num="";
int pos=l+1;
while(pos<r&&str[pos]!='|'){
num+=str[pos];
pos++;
}
string temp="";
pos++;
while(pos<r){
if(str[pos]=='['){
int newl=pos;
int newr=match[pos];
//cout<<"debug "<<temp<<endl;
temp+=solve(newl,newr);
//cout<<"what "<<solve(newl,newr)<<endl;
pos=match[pos]+1;
//printf("pos %d\n",pos);
}
else{
temp+=str[pos];
pos++;
}
//cout<<"debug "<<temp<<endl;
}
int cnt=getint(num);
//printf("cnt %d\n",cnt);
//cout<<"debug "<<temp<<endl;
string temp2=temp;
for(int i=1;i<cnt;i++){
temp+=temp2;
}
//cout<<"debug "<<temp<<endl;
return temp;
}
signed main(){
cin>>str;
for(int i=0;i<str.size();i++)match[i]=-1;
stack<int>s;
for(int i=0;i<str.size();i++){
if(str[i]=='['){
s.push(i);
}
else if(str[i]==']'){
int cur=s.top();s.pop();
match[i]=cur;
match[cur]=i;
}
}
string ans="";
int pos=0;
while(pos<str.size()){
if(str[pos]!='['){
ans+=str[pos];
pos++;
}
else{
ans+=solve(pos,match[pos]);
pos=match[pos]+1;
}
}
cout<<ans<<endl;
return 0;
}
[編程題]逛街
時間限制:C/C++ 2秒,其他語言4秒
空間限制:C/C++ 256M,其他語言512M
小Q在週末的時候和他的小夥伴來到大城市逛街,一條步行街上有很多高樓,共有n座高樓排成一行。
小Q從第一棟一直走到了最後一棟,小Q從來都沒有見到這麼多的樓,所以他想知道他在每棟樓的位置處能看到多少棟樓呢?(當前面的樓的高度大於等於後面的樓時,後面的樓將被擋住)
思路:
裸的單調棧,左右維護一個單調遞減的單調棧,每次查看棧內元素個數就好了
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int a[maxn];
int ans[maxn];
signed main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
stack<int>s;
for(int i=1;i<=n;i++){
ans[i]+=s.size();
//printf("left %d\n",s.size());
while(!s.empty()&&s.top()<=a[i])s.pop();
s.push(a[i]);
}
while(s.size())s.pop();
for(int i=n;i>=1;i--){
ans[i]+=s.size();
//printf("right %d\n",s.size());
while(!s.empty()&&s.top()<=a[i])s.pop();
s.push(a[i]);
}
for(int i=1;i<=n;i++){
printf("%d ",ans[i]+1);
}
return 0;
}
[編程題]假期
時間限制:C/C++ 2秒,其他語言4秒
空間限制:C/C++ 256M,其他語言512M
由於業績優秀,公司給小Q放了 n 天的假,身爲工作狂的小Q打算在在假期中工作、鍛鍊或者休息。他有個奇怪的習慣:不會連續兩天工作或鍛鍊。只有當公司營業時,小Q才能去工作,只有當健身房營業時,小Q才能去健身,小Q一天只能幹一件事。給出假期中公司,健身房的營業情況,求小Q最少需要休息幾天。
思路:
這個題挺有意思,因爲每天只有三種狀態:休息,工作或者健身房,所以dp[i][0,1,2]分別表示前i天最後一天在休息,工作或者健身房的最小休息日,轉移就很好想了:
如果第i天工作,那一定是從昨天休息或者健身房轉移過來;
如果第i天健身,那一定是從昨天工作或者休息轉移過來;
否則,第i天休息,任何狀態都可以轉移過來,天數++。
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int dp[maxn][5];
int a[maxn],b[maxn];
signed main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)scanf("%d",&b[i]);
for(int i=0;i<=n;i++){
for(int j=0;j<=3;j++)dp[i][j]=1e9;
}
for(int i=0;i<=3;i++)dp[0][i]=0;
for(int i=1;i<=n;i++){
if(a[i]==0&&b[i]==0){
int ans=min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]));
dp[i][0]=dp[i][1]=dp[i][2]=ans+1;
}
else{
dp[i][0]=min(min(dp[i-1][1],dp[i-1][2]),dp[i-1][0])+1;
if(a[i]==1){
dp[i][1]=min(dp[i-1][2],dp[i-1][0]);
}
if(b[i]==1){
dp[i][2]=min(dp[i-1][1],dp[i-1][0]);
}
}
}
int ans=1e9;
for(int i=0;i<=2;i++){
ans=min(ans,dp[n][i]);
}
printf("%d\n",ans);
return 0;
}
[編程題]視野爭奪
時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 256M,其他語言512M
小Q在進行一場競技遊戲,這場遊戲的勝負關鍵就在於能否能爭奪一條長度爲L的河道,即可以看作是[0,L]的一條數軸。
這款競技遊戲當中有n個可以提供視野的道具−真視守衛,第i個真視守衛能夠覆蓋區間[xi,yi]。現在小Q想知道至少用幾個真視守衛就可以覆蓋整段河道
思路:
經典區間覆蓋問題,我用線段樹+離散化這種笨方法就好了。
將區間按照左端點排序,維護一個當前能到達的最遠點maxx,那麼當前向L擴張的,一定是左端點在[0,maxx],且右端點最大的那個區間會被我選定,所以線段樹維護區間最大值,記得離散化,每次查詢更新maxx就好了。
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
struct Node{
int l,r;
}node[maxn];
int cmp(const Node a,const Node b){
return a.l<b.l||(a.l==b.l&&a.r<b.r);
}
struct TreeNode{
int l,r;
int maxx;
}Tree[maxn<<2];
void Build(int root,int l,int r){
Tree[root].l=l,Tree[root].r=r;
if(l==r){
Tree[root].maxx=0;
return ;
}
int mid=(l+r)>>1;
Build(root<<1,l,mid);
Build(root<<1|1,mid+1,r);
}
void update(int root,int pos,int val){
if(Tree[root].l==Tree[root].r){
Tree[root].maxx=val;
return ;
}
int mid=(Tree[root].l+Tree[root].r)>>1;
if(pos<=mid){
update(root<<1,pos,val);
}
else{
update(root<<1|1,pos,val);
}
Tree[root].maxx=max(Tree[root<<1].maxx,Tree[root<<1|1].maxx);
}
int query(int root,int l,int r){
if(Tree[root].l>=l&&Tree[root].r<=r){
return Tree[root].maxx;
}
int mid=(Tree[root].l+Tree[root].r)>>1;
if(r<=mid){
return query(root<<1,l,r);
}
else if(l>mid){
return query(root<<1|1,l,r);
}
else{
return max(query(root<<1,l,mid),query(root<<1|1,mid+1,r));
}
}
vector<int>v;
int getid(int cur){
return lower_bound(v.begin(),v.end(),cur)-v.begin()+1;
}
signed main(){
int n,L;
scanf("%d%d",&n,&L);
for(int i=1;i<=n;i++){
scanf("%d%d",&node[i].l,&node[i].r);
v.push_back(node[i].l);
v.push_back(node[i].r);
}
sort(node+1,node+n+1,cmp);
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
Build(1,1,v.size());
for(int i=1;i<=n;i++){
update(1,getid(node[i].l),node[i].r);
}
int maxx=0;
bool flag=true;
int ans=0;
while(maxx<=L){
int maxr=query(1,0,getid(maxx));
if(maxr<=maxx){
flag=false;
break;
}
else{
maxx=maxr;
ans++;
}
}
if(flag){
printf("%d\n",ans);
}
else{
puts("-1");
}
return 0;
}