Description
有一个空的初始队列,支持三种操作:
- 向队首加入一个数。
- 将队列复制一次,放到队首。假设队列中原有 a1,a2,…,an, 变换后为 a1,a2,…,an,a1,a2,…,an。
- 将队列队首元素弹出。
现要你写一个程序,实现这样的队列。
Input
输入数据第一行为测试用例数目 T。之后为 T 组测试用例。
每组测试用例的第一行为操作数 Q。之后的一行有 Q 个数,表示对队列的顺序操作。
某个数字如果是正整数,则表示向队列头加入这个数(操作 1
);如果是 0
,表示对队列进行操 作 2
;如果是-1
,表示弹出队首元素(操作 3
)。
当队列为空的时候,可能会要求你进行第三种操作,此时不用对队列做任何处理。
数据保证:
- T 不超过 100
- Q 不超过 100000
- 表示操作的数不超过 109
- 至多有 5 组测试用例的 Q 超过 1000
Output
每个操作(除了对空队列进行操作 3)应该得到一个结果。操作 1 和 2 的结果是操作后队列的长 度;操作 3 的结果是当前弹出的元素。
因为输出的太多,不要求你将所有的结果输出。而是要求你在每组测试数据的第一个操作前创建 一个为 0 的变量 X,每得到一个新的操作结果,将 X 置为 2333 倍的 X 与当前输出的和取膜 109+7。 即:
X = (X * 2333 + current_result) % MOD
对于第 i 个测试用例,首先输出CASE #i:
之后输出一个空格,然后是结果。
Sample Input
1
5
9 10 0 -1 -1
Sample Output
CASE #1: 458773740
Hint
五次操作的结果分别是:1,2,4,10,9
Source
2017 年"计蒜客杯" 华中师范大学第十五届程序设计竞赛
题解:思路很容易想到,就是用队列的前面一部分去模拟整个队列(因为当队列中元素很多时,就算不停地删除也只与前面的有关,插入同理,复制则不变)
因为都是在头部操作,所以使用deque
有几个陷阱:
1.当判断队列为空时不能用length变量因为有可能取mod之后为0;要用.empty()
2.length要设置为long long以免溢出
3.当对deque进行插入删除操作时不能使用迭代器。
#include<bits/stdc++.h>
using namespace std;
deque<int> dq;
const long long Mod=1000000000+7;
const int maxn=100000+10;
long long length;//this length is mod by Mod
int a[maxn],n;
int backup[maxn<<1];
deque<int>::iterator it_begin,it_end,it;
long long ans;
int main(void)
{
int T;
cin>>T;
for(int ii=1;ii<=T;ii++)
{
length=ans=0;
dq.clear();
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
if((a[i]==-1)&&dq.empty())//empty and pop,no result
continue;
if(a[i]>0)
{
dq.push_front(a[i]);
length=(length+1)%Mod;
ans=(ans*2333+length)%Mod;
}
if(a[i]==-1)
{
ans=(ans*2333+dq.front())%Mod;
dq.pop_front();
length=(length-1+Mod)%Mod;
}
if(a[i]==0)
{
length=length*2;
length%=Mod;
ans=(ans*2333+length)%Mod;
if(dq.size()>200000)
continue;
else
{
int num=0;
for(auto it:dq)
backup[num++]=it;
for(int i=0;i<num;i++)
dq.push_back(backup[i]);
}
}
}
printf("CASE #%d: ",ii);
cout<<ans<<endl;
}
return 0;
}