NOIP2017 赛前模拟 7.24

来源:互联网 发布:意大利的军事实力 知乎 编辑:程序博客网 时间:2024/06/05 07:33

本次考试三道题据出题人的意思都是模板题,T1单调队列模板,T2数位DP模板,T3线段树模板,但由于前两个模板都不熟悉,考试的时候不敢写,线段树也写炸了,最后只有50分。

T1:
题目描述:
在一个包含 n 个元素的数组上,有一个长度为 k 的窗户在从左向右滑动。窗户每滑动到一个位置,我们都可以看到 k 个元素在窗户中。如下的例子所示,假设数组为 [1 3 -1 -3 5 3 6 7],而 k 等于 3 :
这里写图片描述

输入格式
输入的第一行包括两个整数 n,k ,n 表示数组的长度,k 表示窗户的长度。
接下来一行包括 n 个整数,表示这个 n 个元素的数组。

输出格式
输出包含两行,每行包括 n-k+1 个整数。
第一行表示窗户从左到右滑动过程中的最小值。
第二行表示窗户从左到右滑动过程中的最大值。

备注
【数据范围】
对于 100% 的数据,3<=n<=1000000,1<=k<=n,数组中的每个元素均在 int 范围内。

题意:每次选k个数,统计最大值和最小值。所以在我无法打出正解时,想到线段树的区间查询,勉强得了50分,DZY也是线段树但A了,我也没办法。

正解:维护两个单调队列,里面存的是最小值和最大值的下标,一个是维护最小值,一个是维护最大值。每次打新的数压入队尾,先考虑维护最小值的队列,如果前面的数比他还大,说明这些数都无法对答案产生共贡献,就直接r- - (队尾的编号),就将其往前移,最大值也是如此

#include<cstdio>#include<algorithm>#include<cstring>#include<string>#include<cmath>#include<ctime>#include<iomanip>#include<iostream>#include<cctype>using namespace std;const int N =1e6+5;int n,k,q1[N],q2[N],a[N],ans1[N],ans2[N],buf[1000];//---------------------inline int Readint(){    int i=0,f=1; char ch;    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());    if(ch=='-') f=-1,ch=getchar();    for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<1)+(i<<3)+ch-'0';    return i*f;}//---------------------inline void W(int x) //这道题因为数据比较大,输出优化{    if(!x){putchar('0');return;}    if(x<0){putchar('-');x=-x;}    while(x)buf[++buf[0]]=x%10,x/=10;    while(buf[0])putchar('0'+buf[buf[0]--]);}//---------------------int main(){    freopen("window.in","r",stdin);    //freopen("window.out","w",stdout);    n=Readint(),k=Readint();    for(int i=1;i<=n;i++) a[i]=Readint();    int l1=0,l2=0,r1=1,r2=1;    for(int i=1;i<=n;i++){        while(l1<=r1 && q1[l1]<=i-k) l1++; //最小值的队列        while(l2<=r2 && q2[l2]<=i-k) l2++; //最大值的队列         while(l1<=r1 && a[i]<=a[q1[r1]]) r1--; //比他小就一直减        q1[++r1]=i;        while(l2<=r2 && a[i]>=a[q2[r2]]) r2--; //比他大就一直减        q2[++r2]=i;        ans1[i]=a[q1[l1]];        ans2[i]=a[q2[l2]];    }    for(int i=k;i<=n;i++) W(ans1[i]),putchar(' ');    cout<<endl;    for(int i=k;i<=n;i++) W(ans2[i]),putchar(' ');    return 0;}

T2: 裸的数位DP
题目描述:
CLC NOIP2015 惨跪,他依稀记得他的准考证号是 37(其实是假的),现在CLC又将要面临一场比赛,他希望准考证号不出现 37(连续),同时他又十分讨厌 4 ,所以也不希望 4 出现在准考证号中。现在他想知道在 A 和 B 之间有多少合法的准考证号

数位Dp 不解释了

#include<cstdio>#include<algorithm>#include<cstring>#include<string>#include<iomanip>#include<iostream>#include<cmath>#include<ctime>#include<cctype>using namespace std;int x,y,a[20],dp[20][2];//---------------------inline int Readint(){    int i=0,f=1; char ch;    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());    if(ch=='-') f=-1,ch=getchar();    for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<1)+(i<<3)+ch-'0';    return i*f;}//---------------------/*pos是当前枚举到的位数,pre为前一位的数,为了判断是否为3,sta为当前的状态,limit是判断最大能不能枚举到9;*///---------------------inline int dfs(int pos,int pre,int sta,int limit) {    if(pos==-1) return 1;    if(!limit && dp[pos][sta]!=-1) return dp[pos][sta];    int up= limit ? a[pos] : 9;    int tmp=0;    for(int i=0;i<=up;i++){        if(pre==3 && i==7) continue;        if(i==4) continue;        tmp+=dfs(pos-1,i,i==3,limit && i==a[pos]);    }    if(!limit) dp[pos][sta]=tmp;    return tmp;}//---------------------inline int solve(int x){    int pos=0;    while(x) //算出每一位数    {        a[pos++]=x%10;        x=x/10;    }    return dfs(pos-1,-1,0,true);}//---------------------int main(){    x=Readint(),y=Readint();    memset(dp,-1,sizeof(dp));    cout<<solve(y)-solve(x-1); //统计[0,y]和[0,x-1]的值相减    return 0;}

T3:
题目描述:
万恶的大头又出现了!他正在玩一个智障游戏:打怪兽。

现在大头的屏幕上出现了一排怪兽,每只怪兽头上有一个血条,每次大头可以选择一个区间进行攻击,攻击值为 K ,这个区间中血量小于 K 的怪兽都会被大头无情地干掉,当然怪兽不会坐以待毙,对于一个区间的怪兽,他们会在某个时刻血量同时加 X 。

头头虽然很大,但是 IQ 并不高,在座的各位选手都不知道比他高到哪里去了。这个时候大头使出了大招——作弊器,然而大头的作弊器并不高级只能将选择的区间内血量为 7 的倍数的怪兽干掉,问:他能干掉多少怪兽?

输入格式
第一行一个正整数 n ;
接下来 n 行 n 个整数;
再接下来一个正整数 Q ,表示操作的个数;
接下来 Q 行每行若干个整数。如果第一个数是 add ,后接 3 个正整数 a,b,X,表示在区间 [a,b] 内每个数增加 X,如果是 count,表示统计区间 [a,b] 能被 7 整除的个数。

正解:线段树打标记,统计每个区间内数值与7取模和 为 0,1,2,3,4,5,6 的个数 ,最后只用暑促余数为0的个数即可

#include<cstdio>#include<algorithm>#include<cstring>#include<string>#include<cmath>#include<ctime>#include<iomanip>#include<iostream>#include<cctype>using namespace std;const int N = 1e5+5;int a[N],n,m,x,y,z,num;int sum[N<<2][10],add[N<<2],tmp[10];char s[10];//---------------------inline int Readint(){    int i=0,f=1; char ch;    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());    if(ch=='-') f=-1,ch=getchar();    for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<1)+(i<<3)+ch-'0';    return i*f;}//---------------------inline void update(int root){    for(int i=0;i<=6;i++)      sum[root][i]=sum[root<<1][i]+sum[root<<1|1][i];}//---------------------inline void mode(int k,int x){    memset(tmp,0,sizeof(tmp));    for(int i=0;i<=6;i++) tmp[i]=sum[k][i];    for(int i=0;i<=6;i++) sum[k][(i+x)%7]=tmp[i];}//---------------------void Pushdown(int k){    if(add[k])    {        add[k<<1]=(add[k<<1]+add[k])%7,mode(k<<1,add[k]);        add[k<<1|1]=(add[k<<1|1]+add[k])%7,mode(k<<1|1,add[k]);        add[k]=0;    }}//---------------------void build(int k,int l,int r){    if(l==r)    {        sum[k][a[l]]++;        return;    }    int mid=l+r>>1;    build(k<<1,l,mid),build(k<<1|1,mid+1,r);    update(k);}//---------------------void modify(int k,int l,int r,int x,int y,int v){    if(x<=l&&r<=y)    {        memset(tmp,0,sizeof(tmp));        mode(k,v);        add[k]=(add[k]+v)%7;        return;    }    Pushdown(k);    int mid=l+r>>1;    if(y<=mid)modify(k<<1,l,mid,x,y,v);    else if(x>mid)modify(k<<1|1,mid+1,r,x,y,v);    else modify(k<<1,l,mid,x,mid,v),modify(k<<1|1,mid+1,r,mid+1,y,v);    update(k);}//---------------------inline int Query(int k,int l,int r,int x,int y){    if(x<=l&&r<=y) return sum[k][0];    Pushdown(k);    int mid=(l+r)>>1;    if(y<=mid)  return Query(k<<1,l,mid,x,y);    else if(x>mid) return Query(k<<1|1,mid+1,r,x,y);    else return Query(k<<1,l,mid,x,y)+Query(k<<1|1,mid+1,r,x,y);}//---------------------int main(){    freopen("seg.in","r",stdin);    //freopen("seg.out","w",stdout);    n=Readint();    for(int i=1;i<=n;i++) a[i]=Readint()%7;    build(1,1,n);    m=Readint();    for(int i=1;i<=m;i++){        scanf("%s",s);        if(s[0]=='a'){            x=Readint(),y=Readint(),z=Readint()%7;            modify(1,1,n,x,y,z);        }        if(s[0]=='c') {            x=Readint(),y=Readint();            cout<<Query(1,1,n,x,y)<<endl;        }    }    return 0;}
原创粉丝点击