NOIP 模拟 机房欢乐WAK赛

时间:2022-12-16 17:45:36

没错,这渣题,考了60分,确实该好好反思自己了,这就是noip难度的题,现在想想觉得很害怕


NOIP 模拟 机房欢乐WAK赛

题目:

NOIP 模拟 机房欢乐WAK赛
NOIP 模拟 机房欢乐WAK赛
NOIP 模拟 机房欢乐WAK赛
NOIP 模拟 机房欢乐WAK赛
NOIP 模拟 机房欢乐WAK赛
NOIP 模拟 机房欢乐WAK赛
NOIP 模拟 机房欢乐WAK赛


题解:

hao

显然就是一道暴力模拟…我用的指针写,每次暴力strcpy就可以了

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int MAXN=10000;
char str1[MAXN],str2[MAXN];
void del(char *loc){
char *l=loc-1,*r=loc+1;
while(l>=str1&&*l==*loc)l--;
while(*r==*loc)r++;
if(r-l-1>=3){
strcpy(l+1,r);
del(l+1);
}
}
int main(){
freopen("hao.in","r",stdin);
freopen("hao.out","w",stdout);
gets(str1);
int n;
scanf("%d",&n);
for(register int i=1;i<=n;i++){
int loc;char temp;
scanf("%d %c",&loc,&temp);
strcpy(str2,str1+loc);
str1[loc]=temp;
strcpy(str1+loc+1,str2),del(str1+loc);
if(*str1) puts(str1);
else puts("-");
}
return 0;
}

这个故事告诉我们,暴力地用函数(for的1/4时间的str函数),或许有时候可以直接过,原来我写的链表如下,显然要冗杂很多

#include<cstdio>
#include<iostream>
#include<cstring>

char a[3000+3000],col;
struct Point{
int val,tail_qian,tail_hou;
}p[3000+3000],s,t;
int loc,value,tail,n;
void insert(int tail,int loc,int value){
if(s.tail_hou==-2&&t.tail_qian==-1){
p[tail].tail_qian=-1;
p[tail].tail_hou=-2;
s.tail_hou=tail;
t.tail_qian=tail;
p[tail].val=value;
printf("%c\n",value+'A');
return;
}
if(p[loc].tail_qian==-1&&p[loc].tail_hou!=-2){
s.tail_hou=tail;
p[tail].tail_qian=-1;
p[tail].val=value;
p[tail].tail_hou=loc;
p[p[tail].tail_hou].tail_qian=tail;
}else if(p[loc].tail_hou==-2&&p[loc].tail_qian!=-1){
t.tail_qian=tail;
p[tail].tail_hou=-2;
p[tail].val=value;
p[tail].tail_qian=p[loc].tail_qian;
p[loc].tail_qian=tail;
}else if(p[loc].tail_qian==-1&&p[loc].tail_hou==-2){
s.tail_hou=tail;
p[tail].tail_qian=-1;
p[tail].tail_hou=loc;
p[loc].tail_qian=tail;
p[tail].val=value;
}else if(p[loc].tail_qian!=-1&&p[loc].tail_hou!=-2){
p[tail].tail_qian=p[loc].tail_qian;
p[tail].tail_hou=loc;
p[p[tail].tail_qian].tail_hou=tail;
p[p[tail].tail_hou].tail_qian=tail;
p[tail].val=value;
}
int from=tail,to=tail;
int valuetemp=value;
int cntt=1;
while(true){
while(p[from].tail_qian!=-1&&p[p[from].tail_qian].val==valuetemp){
from=p[from].tail_qian;
cntt++;
}
while(p[to].tail_hou!=-2&&p[p[to].tail_hou].val==valuetemp){
to=p[to].tail_hou;
cntt++;
}
if(cntt<3) break;
from=p[from].tail_qian;to=p[to].tail_hou;
if(from==-1&&to==-2){
s.tail_hou=-2;
t.tail_qian=-1;
printf("-\n");return;
}
if(from==-1){
p[to].tail_qian=-1;
s.tail_hou=to;
}
if(to==-2){
p[from].tail_hou=-2;
t.tail_qian=from;
}
if(from!=-1&&to!=-2){
p[from].tail_hou=to;
p[to].tail_qian=from;
}
if(p[from].val!=p[to].val) break;
valuetemp=p[from].val;
cntt=2;
}
int now=s.tail_hou;
while(now!=-2){
printf("%c",'A'+p[now].val);
now=p[now].tail_hou;
}
printf("\n");
}
int main(){
freopen("hao.in","r",stdin);
freopen("hao.out","w",stdout);
scanf("%s",a);
int lena=strlen(a);tail=lena-1;
p[0].tail_hou=1;p[0].tail_qian=-1;p[0].val=a[0]-'A';
s.tail_hou=0;
t.tail_qian=lena-1;
for(register int i=1;i<lena-1;i++){
p[i].tail_hou=i+1;
p[i].tail_qian=i-1;
p[i].val=a[i]-'A';
}
p[lena-1].tail_hou=-2;
p[lena-1].tail_qian=lena-2;
p[lena-1].val=a[lena-1]-'A';
scanf("%d",&n);
for(register int i=1;i<=n;i++){
char tt;
scanf("%d%c%c",&loc,&tt,&col);
value=col-'A';
loc++;
int now=s.tail_hou,cnt=1;
while(p[now].tail_hou!=-2){
if(cnt==loc) break;
cnt++;
now=p[now].tail_hou;
}
tail++;
insert(tail,now,value);
}
}

kun

这道题…显然也是贪心水题,但是坑点很多啊,首先要判空,然后思路是先pop大的,再pop小的,然而实际上还可能要pop已经在栈里的…而且即使直接pop没进栈的,instack也要打成true

#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
stack<int>stk;
int n,now;
bool instack[2000000+10];
int main(){
freopen("kun.in","r",stdin);
freopen("kun.out","w",stdout);
scanf("%d",&n);
int ned=n;
for(register int i=1;i<=n;i++){
scanf("%d",&now);
if(now==ned){
printf("%d ",now);
ned--; instack[now]=true;
while(instack[ned])ned--;
while(!stk.empty()&&stk.top()>ned)printf("%d ", stk.top()), stk.pop();
}
else{
instack[now]=true;
stk.push(now);
}
}
while(!stk.empty()){
int temp=stk.top();
printf("%d ",temp);
stk.pop();
}
return 0;
}
/*
15
6 7 14 9 15 1 4 5 8 3 13 12 10 2 11
*/

nan

这道题一看题目就难到了
显然这道题是找规律…然而我是找不出规律的,所以我们分块来看…把数据按照一定的规律分块,记录每个块的起始数字和终止数字,记录块的数字总数前缀和,再二分一下就可以很快得出答案了,而这个块具体是怎么搞得呢,观察下面的图

NOIP 模拟 机房欢乐WAK赛

稍微模拟出这样的一个数列,我们发现一个很神奇的事情就是每个数字的个数竟然又是这样的一个数列,现在我们进行分块,从原数列中的2衍生出来的分一块,3衍生出来的分一块,大概是这么个操作
NOIP 模拟 机房欢乐WAK赛
然后我们进一步分块

NOIP 模拟 机房欢乐WAK赛

震惊地发现,最后红线分出来的块之中含有的第一行元素的个数,竟然变成了1 * 1 | 2 * 2 + 2 * 3 | 3 * 4 + 3 * 5 |…
等等,这样分出来的块含的元素个数,不就是等差数列可以求的嘛,所以看代码吧

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
const long long MAXN=2000000+10;
const long long lk=1e9+7;
int n,t;
long long f[MAXN],last[MAXN],len,l,r,cnt;
struct Block{long long from,to;}block[MAXN];
int main(){
freopen("nan.in","r",stdin);
freopen("nan.out","w",stdout);
last[1]=1;last[2]=3;len=2;
block[1].from=block[1].to=1;
block[2].from=2;block[2].to=3;
for(register int i=3;i<=2000000;i++){
last[i]=last[i-1]+len;
block[i].from=last[i-1]+1;
block[i].to=last[i];
if(i>=last[len])len++;
}
for(register int x=1;x<=2000000;x++){
f[x]=f[x-1]+(block[x].to-block[x].from+1)*x*(block[x].to+block[x].from)/2%lk;
f[x]%=lk;
}
scanf("%d",&t);
for(register int i=1;i<=t;i++){
scanf("%d",&n);
l=1;r=2000000;
while(l<=r){
int mid=(l+r)>>1;
if(block[mid].to<n) l=mid+1;
else r=mid-1;
}//二分查找
cnt=f[r];
cnt+=(r+1)*(n-block[r].to)*(block[r+1].from+n)/2%lk;
cnt%=lk;
printf("%I64d\n",cnt);
}
return 0;
}