牛客:14326.14666.15029.14847.15137
14326:Rails
题意描述: 有一列n截车厢的火车在A端每个车厢上都有标号,在火车运行的过程需要进入一个岔口,可以选择不出去或者出去,完全出去后根据车厢上面的数字读出,看能否组成目标数。
解题思路:将目标数放到一个数组里面,再定义一个栈,定义两个数A i ,A表示目前准备从A驶出的车辆,i表示现在B中已有几辆车匹配。进入while循环进行判断是否在岔口停留或者出去,如果A中准备驶出的车 与 B中需要的车 一致,把该车不经过岔口直接驶入B,如果岔口最上面的车厢 与 B中需要的车厢一致 把该车驶出岔口并驶入B出栈,当A中车未完全驶出时,把A中最前面的车驶入岔口等待进栈,如果不符合上述情况 说明给定顺序错误,将i标为-1,最后判断i是否为-1,是就输出No,否者输出yes。
//1、2、3进,3、2、1出 次序321。
//1进,1出,2进,2出,3进,3出 次序123。
//1进,2进,2出,1出,3进,3出 次序213。
//1进,1出,2进,3进,3出,2出 次序132。
//1进,2进,2出,3进,3出,1出 次序231。
#include<cstdio>
#include<stack>
using namespace std;
int n;
int b[1010];
int main()
{
while(scanf("%d",&n)&&n)
{
while(1)
{
for(int i=0;i<n;i++)
{//因为每次我们只使用b数组中的[0,n)的值,而新值会覆盖旧值,无需清空,栈清空无函数while(!s.empty()) s.pop();
scanf("%d",&b[i]);
if(b[i]==0)
{//当输入为0时,说明这组数据结束
break;
}
}
if(b[0]==0)
{//当输入为0时,说明这组数据结束,跳出该循环,准备接受输入另一个n
break;
}
stack<int> c;//岔口定义成栈
int a=1,i=0;//a表示目前准备从a驶出的车辆,i表示现在匹配b中的第几辆车
while(i<n)
{
if(a==b[i])
{//如果a中准备驶出的车 与 b中需要的车一致,把该车不经过岔口直接驶入b
a++;
i++;
}else if(!c.empty()&&c.top()==b[i])
{//如果c最上面的车厢 与 b中需要的车厢一致 把该车驶出岔口并驶入b
c.pop();
i++;
}else if(a<=n)
{//当a中车未完全驶出时,把a中最前面的车驶入岔口等待
c.push(a);
a++;
}else
{//如果不符合上述情况 说明给定顺序错误,将i标为-1
i=-1;
break;
}
}
if(i==-1){
printf("No\n");
}
else{
printf("Yes\n");
}
}
printf("\n");//!
}
return 0;
}
14666最优屏障
由于屏障作用后使得隔离两侧的哨兵彼此不能看到另一侧,即只能在同一侧内观察,故要试图找出出每个隔离位置前面及后面的防御力,由于屏障的隔离性,选择用一个类似前缀数组,一个类似后缀数组来分别存从1-i每个位置往前看和往后看的防御力值,由于上述式子的限定,其实对于每一个位置,在看的一座较高山后面的较矮山都看不到了,由于从头到目标的前一个位置都要求一个高度递减的单调性,故采用栈结构来存每座山,遍历时每次遇到比当前山矮的山都pop掉,因为该矮山对之后的山根本就没有贡献,这样求一次前缀,一次后缀。最后维护的答案是pre(n)(或suf(n))-(pre(i-1)+suf(i)),即之前的总值减掉屏蔽后的值,取max即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
#define maxn 50005
int a[maxn],pre[maxn],suf[maxn];
stack<int>st;
int main()
{
int i,j;
int n,m;
int t;
int k=0;
scanf("%d",&t);
while(t--)
{
memset(pre,0,sizeof(pre));
memset(suf,0,sizeof(suf));
while(!st.empty())
{
st.pop();
}
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(i=1;i<=n;i++)
{
int now=0;
pre[i]=pre[i-1];//计算的是往前看时能到达的最大防御力前缀和;
while(!st.empty()&&st.top()<a[i])//计数同时更新山的位置,因为高度低的之前的那些山在目前这座山的屏蔽下都不能被之后的山观察到;
{
now++;//可行解+1;
st.pop();
}
if(!st.empty())
{
pre[i]+=(now+1);//因为只是计算了比它矮的山,当前高山还没有记录,所以要+1;
}
else
{
pre[i]+=now;
}
st.push(a[i]);
}
while(!st.empty())
{
st.pop();//之后要计算往后看的,要把栈先清空;
}
//同理,每次计算后缀;
for(i=n;i>=1;i--)
{
suf[i]=suf[i+1];
int now=0;
while(!st.empty()&&st.top()<a[i])
{
st.pop();
now++;
}
if(!st.empty())
{
suf[i]+=(now+1);
}
else
{
suf[i]+=now;
}
st.push(a[i]);
}
//之后就遍历,每个i的位置之前放置屏障取最大值;
int maxx=-1;
int maxpos;//记录位置;
//这里记录当前减小值的式子为:pre[n](即所有防御力的和)-(pre[i-1]+suf[i])(即加完屏障后,屏障前的只能往前看,屏障后的只能往后看);
//两者之差即为减小值;
for(i=1;i<=n;i++)
{
if((pre[n]-(pre[i-1]+suf[i]))>maxx)
{
maxx=pre[n]-(pre[i-1]+suf[i]);
maxpos=i;
}
}
printf("Case #%d: %d %d\n",++k,maxpos,maxx);
}
return 0;
}