时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 256M,其他语言512M
小Q想要给他的朋友发送一个神秘字符串,但是他发现字符串的过于长了,于是小Q发明了一种压缩算法对字符串中重复的部分进行了压缩,对于字符串中连续的m个相同字符串S将会压缩为[m|S](m为一个整数且1<=m<=100),例如字符串ABCABCABC将会被压缩为[3|ABC],现在小Q的同学收到了小Q发送过来的字符串,你能帮助他进行解压缩么?
大模拟,递归的将所有[]区间的内容暴力转换就好了,不得不说这个题放第一个比较折磨人
#include
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>str;
for(int i=0;is;
for(int i=0;i
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 256M,其他语言512M
小Q在周末的时候和他的小伙伴来到大城市逛街,一条步行街上有很多高楼,共有n座高楼排成一行。
小Q从第一栋一直走到了最后一栋,小Q从来都没有见到这么多的楼,所以他想知道他在每栋楼的位置处能看到多少栋楼呢?(当前面的楼的高度大于等于后面的楼时,后面的楼将被挡住)
裸的单调栈,左右维护一个单调递减的单调栈,每次查看栈内元素个数就好了
#include
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]);
stacks;
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
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
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>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));
}
}
vectorv;
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;
}