EZ 2018 05 13 NOIP2018 模拟赛(十三)

这次的比赛真心水,考时估分240,然后各种悠闲乱逛

然后测完T1数组开小了炸成40,T2,T3都没开long long,T2炸成20,T3爆0

掉回1600+的深渊,但是还有CJJ dalao比我更惨

T1

这道题就比较simple了,很显然用数据结构乱优化

貌似有很多种解法:单调队列,堆,线段树等等

我主要就讲一下我考试的时候YY出来的线段树

首先我们发现一个性质:对于n次操作之后,序列就进入循环

然后我们只需要处理处前n次询问就可以O(n)处理了

我们开一个前缀和记录原串中1的个数,然后设一个数组f[i]表示i左边k的长度范围内(包括它自己)一共有几个1(不足k也允许)

然后我们发现将一个数从尾部移到最前面,有两种情况:

  • 如果这个数是0,那么只需要把它自己的f[i]修改成0即可
  • 如果这个数是1,那么只需要把它自己的f[i]就改成1,并且把队头的前k-1项的f[]值加1

然后我们之间把初始数组右移n个长度(前面的为循环做准备),然后上线段树即可

然而我f数组忘记<<1了,而且那个字符串数组也看错了范围dog!!!

CODE

#include<cstdio>
#include<cstring>
using namespace std;
const int N=100005;
struct segtree
{
    int add,s;
}tree[N<<3];
int a[N],f[N<<1],sum[N],ans[N],n,k,q,tot;
char s[N<<1];
inline void read(int &x)
{
    x=0; char ch=getchar();
    while (ch<‘0‘||ch>‘9‘) ch=getchar();
    while (ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
}
inline void write(int x)
{
    if (x/10) write(x/10);
    putchar(x%10+‘0‘);
}
inline int max(int a,int b)
{
    return a>b?a:b;
}
inline void up(int root)
{
    tree[root].s=max(tree[root<<1].s,tree[root<<1|1].s);
}
inline void down(int root)
{
    if (tree[root].add)
    {
        tree[root<<1].add+=tree[root].add;
        tree[root<<1|1].add+=tree[root].add;
        tree[root<<1].s+=tree[root].add;
        tree[root<<1|1].s+=tree[root].add;
        tree[root].add=0;
    }
}
inline void build(int root,int l,int r)
{
    if (l==r)
    {
        tree[root].s=f[l];
        return;
    }
    int mid=l+r>>1;
    build(root<<1,l,mid); build(root<<1|1,mid+1,r);
    up(root);
}
inline void updata(int root,int l,int r,int id)
{
    if (l==r)
    {
        tree[root].s=0;
        return;
    }
    int mid=l+r>>1;
    down(root);
    if (id<=mid) updata(root<<1,l,mid,id); else updata(root<<1|1,mid+1,r,id);
    up(root);
}
inline void modify(int root,int l,int r,int beg,int end)
{
    if (l>=beg&&r<=end)
    {
        tree[root].s+=1; tree[root].add+=1;
        return;
    }
    int mid=l+r>>1;
    down(root);
    if (beg<=mid) modify(root<<1,l,mid,beg,end);
    if (end>mid) modify(root<<1|1,mid+1,r,beg,end);
    up(root);
}
int main()
{
    //freopen("A.in","r",stdin); freopen("A.out","w",stdout);
    register int i;
    read(n); read(k); read(q);
    for (i=1;i<=n;++i)
    {
        read(a[i]); sum[i]=sum[i-1]+a[i];
        if (i>=k) f[i+n]=sum[i]-sum[i-k]; else f[i+n]=sum[i];
    }
    build(1,1,n<<1);
    ans[0]=tree[1].s;
    for (i=1;i<=n;++i)
    {
        updata(1,1,n<<1,(n<<1)-i+1);
        if (a[n-i+1]) modify(1,1,n<<1,n-i+1,n-i+k);
        ans[i]=tree[1].s;
    }
    for (scanf("%s",s+1),i=1;i<=q;++i)
    if (s[i]==‘?‘) write(ans[tot]),putchar(‘\n‘); else { if (++tot==n) tot=0; }
    return 0;
}

T2

这题意一看就是暴力数据结构,然而我没开long long

我们通过观察发现2操作满足一个很凶猛的性质:前面的操作不会影响后面的操作

因此我们可以从前往后推一下,对于所有的操作2,将它操作的区间中的所有操作的次数+=目前这个操作的次数(默认为1)

然后最后我们得到了所有操作的次数,然后对于操作1上线段树 or 树状数组+差分即可

线段树CODE

#include<cstdio>
using namespace std;
typedef long long LL;
const LL N=100005,mod=1e9+7;
struct time_segtree
{
    LL add[N<<2],sum[N<<2];
    inline void up(LL root)
    {
        sum[root]=(sum[root<<1]+sum[root<<1|1])%mod;
    }
    inline void down(LL root,LL l,LL r)
    {
        if (add[root])
        {
            add[root<<1]=(add[root<<1]+add[root])%mod;
            add[root<<1|1]=(add[root<<1|1]+add[root])%mod;
            sum[root<<1]=(sum[root<<1]+add[root]*l)%mod;
            sum[root<<1|1]=(sum[root<<1|1]+add[root]*r)%mod;
            add[root]=0;
        }
    }
    inline void modify(LL root,LL l,LL r,LL beg,LL end,LL k)
    {
        if (l>=beg&&r<=end)
        {
            sum[root]=(sum[root]+k*(r-l+1))%mod;
            add[root]=(add[root]+k)%mod;
            return;
        }
        LL mid=l+r>>1;
        down(root,mid-l+1,r-mid);
        if (beg<=mid) modify(root<<1,l,mid,beg,end,k);
        if (end>mid) modify(root<<1|1,mid+1,r,beg,end,k);
        up(root);
    }
    inline LL query(LL root,LL l,LL r,LL id)
    {
        if (l==r) return sum[root];
        LL mid=l+r>>1;
        down(root,mid-l+1,r-mid);
        if (id<=mid) return query(root<<1,l,mid,id); else return query(root<<1|1,mid+1,r,id);
    }
}T;
struct ans_segtree
{
    LL add[N<<2],sum[N<<2];
    inline void up(LL root)
    {
        sum[root]=(sum[root<<1]+sum[root<<1|1])%mod;
    }
    inline void down(LL root,LL l,LL r)
    {
        if (add[root])
        {
            add[root<<1]=(add[root<<1]+add[root])%mod;
            add[root<<1|1]=(add[root<<1|1]+add[root])%mod;
            sum[root<<1]=(sum[root<<1]+add[root]*l)%mod;
            sum[root<<1|1]=(sum[root<<1|1]+add[root]*r)%mod;
            add[root]=0;
        }
    }
    inline void modify(LL root,LL l,LL r,LL beg,LL end,LL k)
    {
        if (l>=beg&&r<=end)
        {
            sum[root]=(sum[root]+k*(r-l+1))%mod;
            add[root]=(add[root]+k)%mod;
            return;
        }
        LL mid=l+r>>1;
        down(root,mid-l+1,r-mid);
        if (beg<=mid) modify(root<<1,l,mid,beg,end,k);
        if (end>mid) modify(root<<1|1,mid+1,r,beg,end,k);
        up(root);
    }
    inline LL query(LL root,LL l,LL r,LL id)
    {
        if (l==r) return sum[root];
        LL mid=l+r>>1;
        down(root,mid-l+1,r-mid);
        if (id<=mid) return query(root<<1,l,mid,id); else return query(root<<1|1,mid+1,r,id);
    }
}A;
struct data
{
    LL opt,x,y;
}q[N];
LL n,m;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(LL &x)
{
    x=0; char ch=tc();
    while (ch<‘0‘||ch>‘9‘) ch=tc();
    while (ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=tc();
}
inline void write(LL x)
{
    if (x/10) write(x/10);
    putchar(x%10+‘0‘);
}
int main()
{
    //freopen("B.in","r",stdin); freopen("B.out","w",stdout);
    register LL i;
    read(n); read(m);
    for (i=1;i<=m;++i)
    read(q[i].opt),read(q[i].x),read(q[i].y);
    for (i=m;i>=1;--i)
    {
        T.modify(1,1,m,i,i,1);
        if (q[i].opt==2) { LL x=T.query(1,1,m,i); T.modify(1,1,m,q[i].x,q[i].y,x); }
    }
    for (i=1;i<=m;++i)
    if (q[i].opt==1) { LL x=T.query(1,1,m,i); A.modify(1,1,n,q[i].x,q[i].y,x); }
    for (i=1;i<=n;++i)
    write(A.query(1,1,n,i)),putchar(‘ ‘);
    return 0;
}

T3

比较玄学的卢卡斯定理乱推

反正我对这种数学的东西没什么兴趣,还是打打暴力好了

这里的暴力也比较有技巧,我们搞一下每一个点第x天的权值,记录下来,因为既可以用来推后面的,也可以用来O(1)求答案

40ptsCODE

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const LL N=1005;
struct edge
{
    LL to,next;
}e[N<<1];
LL head[N],w[N][N],a[N],n,q,x,y,root,cnt,m;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(LL &x)
{
    x=0; char ch=tc();
    while (ch<‘0‘||ch>‘9‘) ch=tc();
    while (ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=tc();
}
inline void write(LL x)
{
    if (x/10) write(x/10);
    putchar(x%10+‘0‘);
}
inline void add(LL x,LL y)
{
    e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt;
}
inline LL max(LL a,LL b)
{
    return a>b?a:b;
}
inline void DFS(LL now,LL fa)
{
    bool flag=1; register LL i,j;
    for (i=head[now];i!=-1;i=e[i].next)
    if (e[i].to!=fa)
    {
        flag=0;
        DFS(e[i].to,now);
    }
    if (flag) for (i=1;i<=m;++i) w[now][i]=w[now][0]; else
    {
        for (i=1;i<=m;++i)
        for (w[now][i]=w[now][i-1],j=head[now];j!=-1;j=e[j].next)
        if (e[j].to!=fa) w[now][i]^=w[e[j].to][i];
    }
}
int main()
{
    //freopen("C.in","r",stdin); freopen("C.out","w",stdout);
    register LL i;
    memset(head,-1,sizeof(head));
    memset(e,-1,sizeof(e));
    read(n); read(q);
    for (i=1;i<n;++i)
    read(x),read(y),add(x,y),add(y,x);
    for (i=0;i<n;++i)
    read(w[i][0]);
    for (i=1;i<=q;++i)
    read(a[i]),m=max(m,a[i]);
    DFS(root,-1);
    for (i=1;i<=q;++i)
    write(w[root][a[i]]),putchar(‘\n‘);
    return 0;
}

原文地址:https://www.cnblogs.com/cjjsb/p/9038047.html

时间: 2024-10-09 13:28:52

EZ 2018 05 13 NOIP2018 模拟赛(十三)的相关文章

EZ 2018 05 06 NOIP2018 慈溪中学集训队互测(五)

享受爆零的快感 老叶本来是让初三的打的,然后我SB的去凑热闹了 TM的T2写炸了(去你妹的优化),T1连-1的分都忘记判了,T3理所当然的不会 光荣革命啊! T1 思维图论题,CHJ dalao给出了正解但-1输成0了缅怀 而且这题不能用读优玄学 思路也很新奇,先跑一遍MST,判断是否有无解的情况 然后看一下MST中与1相连的边有几条 如果小于k那么我们把所有与1相连的边减上一个值使它们优先被选,然后跑MST 大于k就加上去即可 注意到这个值可以二分,因此不停做MST即可 CODE #inclu

2018.8.6 Noip2018模拟测试赛(十九)

日期: 八月六号  总分: 300分  难度: 提高 ~ 省选    得分: 10分(MMP) 题目目录: T1:Tree T2:异或运算 T3:Tree Restoring 赛后反思: Emmmmmmm…… 一直在打第一题…… 结果考完才发现dp少了一种情况…… 除此之外,我无话可说…… Emmmmmm…… 题解: T1:Tree 树形背包dp,设$f[i][j][k(0/1/2)]$为$i$的子树中,选$j$条边,0:从$i$出发,到$i$结束/1:从$i$出发,到$i$的某个后代结束/2:

5.13 校内模拟赛

... 果然是dalao们做难题做多了后 简单题水不起来了吗.. 5.13解题报告 300分 T1写了差不多30~40分钟 T2写了不到5min (当时怀疑有坑..) T3推了大概1个多小时的式子, 然后又加上调试差不多一个半小时 时间分配就这样..感觉T2出的太过简单了..直接是个模板 T1 并查集 + 乱搞 T2 快速幂模板 T3 Dp T1 : codevs 2796 最小完全图 二次联通门 : codevs 2796 最小完全图 /* codevs 2796 最小完全图 并查集 + 乱搞

2018.02.12 noip模拟赛T2(未完待续)

二兵的赌注 Description游戏中,二兵要进入了一家奇怪的赌场.赌场中有n个庄家,每个庄家都可以猜大猜小,猜一次一元钱.每一次开彩前,你都可以到任意个庄家那里下赌注.如果开彩结果是大,你就可以得到你之前猜大的庄家相应的ai元钱.如果开彩结果是小,你就可以得到你之前猜小的庄家相应的bi元钱.你可以在同一个庄家那里既猜大又猜小,(这样是两块钱),也可以什么都不猜(这样不用钱).问怎么样下注,才能赢得最多的有保障的钱.有保障的钱指不管开彩结果是大是小,你都能够赢得相应的钱.你能帮助他计算这个值吗

2019.03.13 ZJOI2019模拟赛 解题报告

得分: \(55+12+10=77\)(\(T1\)误认为有可二分性,\(T2\)不小心把\(n\)开了\(char\),\(T3\)直接\(puts("0")\)水\(10\)分) \(T1\):Bug 级的存在 感觉只有我这种智障才会觉得这题有可二分性. 显然,若要一段区间能够成为公差为\(d\)的等差序列,则一个基本要求就是这段区间要模\(d\)同余. 因此,我们首先自然就是把每段同余的区间单独抠出来处理. 然后我们把这段区间内的数同整除\(d\). 但要注意,正数和负数同整除\

2018 蓝桥杯省赛 B 组模拟赛(一)

2018 蓝桥杯省赛 B 组模拟赛(一) A.今天蒜头君带着花椰妹和朋友们一起聚会,当朋友们问起年龄的时候,蒜头君打了一个哑谜(毕竟年龄是女孩子的隐私)说:“我的年龄是花椰妹年龄个位数和十位数之和的二倍”. 花椰妹看大家一脸懵逼,就知道大家也不知道蒜头君的年龄,便连忙补充道:“我的年龄是蒜头君个位数和十位数之和的三倍”. 请你计算:蒜头君和花椰妹年龄一共有多少种可能情况? 提醒:两位的年龄都是在 [10,100)[10,100) 这个区间内. 题解: 暴力枚举 answer: 1 代码如下: #

ZROI提高组模拟赛05总结

ZROI提高组模拟赛05总结 感觉是目前为止最简单的模拟赛了吧 但是依旧不尽人意... T1 有一半的人在30min前就A掉了 而我花了1h11min 就是一个简单的背包,我硬是转化了模型想了好久,生生把一个弱智题变成了一个不可做题 最后竟然在转化两次后的模型上以为自己做出来了 这个题比别人多花的1h左右的时间,而且只得到了30分,成为了这场比赛失败的关键因素 T2 依旧是一道简单题 有人20min之内就A掉了 感觉放在CF里最多算一道Div2 D,还是简单的那种 可是我又一次想复杂了 大意就是

2018/5/24模拟赛总结

shzr带病AK虐爆全场... T1n皇后: 这题没啥好说的... T2有重复元素的排列问题: [问题描述] 设R={ r1, r2 , -, rn}是要进行排列的n个元素.其中元素r1, r2 , -, rn可能相同.试设计一个算法,列出R的所有不同排列. [编程任务] 给定n 以及待排列的n 个元素.计算出这n 个元素的所有不同排列. [输入格式] 由perm.in输入数据.文件的第1 行是元素个数n,1≤n≤500.接下来的1 行是待排列的n个元素. [输出格式] 计算出的n个元素的所有不

【2018.11.22】ctsc2018(模拟赛!)

太蠢了……$noip$ 后第一次模拟赛竟然是这样的……完全就是打击自信 / 降智…… 1. 假面 一道神仙概率 $dp$!第一次写…… 拿到题就发现血量 $m_i$ 的上限只有 $100$! 然后 $0$ 操作就可以用 $rate(i,j)$ 动态维护第 $i$ 个人血量为 $j$ 的概率啦. $1$ 操作比较麻烦(但是它故意弄得很少). 设 $live_i$ 和 $dead_i$ 分别为 $1$ 操作范围内的第 $i$ 个人活着和死了的概率,$g_{i,j}$ 是除 $i$ 以外有 $j$ 个