首页 > 其他分享 >冲刺清北营 7

冲刺清北营 7

时间:2023-04-27 16:15:49浏览次数:32  
标签:rt cnt 大水 没切 int tree 冲刺 清北营

ZROI 2022 省选十连测 Day7。我在验 23 的 Day7 的时候突然考了 22 的 Day7。

今天 T3 充分的说明了我脑子有问题的事实。属于是推式子推魔怔了忘了这是个直接 FWT 就能出的东西。可能以后早上应该吃饱一点来应对数据结构后边跟着数学的情况。

为啥 T1 都写这么快,就我调到十一点。

a

首先不考虑 \(0\)。那么一个序列合法则所有元素和为偶数。那么扫描线变成 \(01\) 串支持区间异或,区间历史和。这个可以线段树每个节点多维护个有几个历史版本为 \(0\),几个历史版本为 \(1\) 的标记来做到(然而这玩意写死我了直接导致 T3 没切)。我是用所有的情况减掉不合法的,也就是异或和为 \(1\) 的。

然后考虑加上 \(0\) 的情况。此时 \(0\) 把整个序列分成若干段。称整段为夹在两个 \(0\) 之间的段。仍然线段树扫描线,设当前到 \(i\),把整个序列分成三段 \([1,pre),[pre,last),[last,i]\)。第一段的结尾是最后一个不合法的整段,即这一段不会再对答案造成贡献,是被删除的段。第二段的开头 \(pre\) 是最后一个不合法的整段的结尾 \(0\) 处,代表这些整段是合法的,可能会造成贡献。第三个整段是当前扫到的整段。每次扫到一个数,第一段历史和区间 \(+1\) 表示无贡献,然后将第三个整段异或 \(a_i \wedge 1\),这样就可以通过 \(last\) 位置的 \(0/1\) 判断第二段是否有贡献,做区间历史和 \(+1\) 或是区间异或 \(0\)。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#define int long long
using namespace std;
#define lson rt<<1
#define rson rt<<1|1
int n,m,a[500010],ans[500010];
int read(){
    int x=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))x=10*x+ch-'0',ch=getchar();
    return x;
}
struct node{
    int sum,sum2,cnt[2],lz,len,lz2;
}tree[2000010];
void build(int rt,int l,int r){
    tree[rt].len=r-l+1;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(lson,l,mid);build(rson,mid+1,r);
}
void pushup(int rt){
    tree[rt].sum=tree[lson].sum+tree[rson].sum;
    tree[rt].sum2=tree[lson].sum2+tree[rson].sum2;
}
void pushtag(int rt,int sum,int cnt[],int lz){
    tree[rt].sum2+=tree[rt].sum*cnt[0]+(tree[rt].len-tree[rt].sum)*cnt[1];
    tree[rt].cnt[0]+=cnt[tree[rt].lz];tree[rt].cnt[1]+=cnt[tree[rt].lz^1];
    if(lz)tree[rt].sum=tree[rt].len-tree[rt].sum,tree[rt].lz^=lz;
}
void pushdown(int rt){
    pushtag(lson,tree[rt].sum,tree[rt].cnt,tree[rt].lz);
    pushtag(rson,tree[rt].sum,tree[rt].cnt,tree[rt].lz);
    if(tree[rt].lz2){
        tree[lson].sum2+=tree[lson].len*tree[rt].lz2;tree[rson].sum2+=tree[rson].len*tree[rt].lz2;
        tree[lson].lz2+=tree[rt].lz2;tree[rson].lz2+=tree[rt].lz2;
        tree[rt].lz2=0;
    }
    tree[rt].cnt[0]=tree[rt].cnt[1]=tree[rt].lz=0;
}
void update(int rt,int L,int R,int l,int r,int val){
    if(l>r)return;
    if(l<=L&&R<=r){
        if(val){
            tree[rt].lz^=1;tree[rt].sum=tree[rt].len-tree[rt].sum;
        }
        tree[rt].sum2+=tree[rt].sum;tree[rt].cnt[tree[rt].lz]++;
        return;
    }
    pushdown(rt);
    int mid=(L+R)>>1;
    if(l<=mid)update(lson,L,mid,l,r,val);
    if(mid<r)update(rson,mid+1,R,l,r,val);
    pushup(rt);
}
void update(int rt,int L,int R,int l,int r){
    if(l>r)return;
    if(l<=L&&R<=r){
        tree[rt].sum2+=tree[rt].len;tree[rt].lz2++;
        return;
    }
    pushdown(rt);
    int mid=(L+R)>>1;
    if(l<=mid)update(lson,L,mid,l,r);
    if(mid<r)update(rson,mid+1,R,l,r);
    pushup(rt);
}
int query(int rt,int L,int R,int l,int r){
    if(l<=L&&R<=r)return tree[rt].sum2;
    pushdown(rt);
    int mid=(L+R)>>1,val=0;
    if(l<=mid)val+=query(lson,L,mid,l,r);
    if(mid<r)val+=query(rson,mid+1,R,l,r);
    return val;
}
int query(int rt,int L,int R,int pos){
    if(L==R)return tree[rt].sum;
    pushdown(rt);
    int mid=(L+R)>>1;
    if(pos<=mid)return query(lson,L,mid,pos);
    else return query(rson,mid+1,R,pos);
}
vector<pair<int,int> >q[500010];
int C(int n){
    return n*(n+1)>>1;
}
signed main(){
    n=read();m=read();
    build(1,1,n);
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=m;i++){
        int l=read(),r=read();
        q[r].push_back(make_pair(l,i));
    }
    int pre=1,last=1,cnt=0;
    for(int i=1;i<=n;i++){
        update(1,1,n,1,pre-1);
        update(1,1,n,last,i,a[i]&1);
        if(query(1,1,n,last)==1)update(1,1,n,pre,last-1);
        else update(1,1,n,pre,last-1,0);
        for(pair<int,int>p:q[i])ans[p.second]=C(i-p.first+1)-query(1,1,n,p.first,i);
        if(a[i]==0){
            if(query(1,1,n,last)==1)pre=last;
            last=i;
        }
    }
    for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
    return 0;
}

b

赛时一车假的暴力艹掉了这题。然而我调完 T1 已经十一点了 T2 T3 还没想就敲了两个暴力,主要是身体条件不支持。

结论是随机区间按左端点排序后右端点的 LIS 期望是 \(O(\sqrt q)\) 的。那么询问可以分成 \(O(\sqrt q)\) 组,每组修改集合是嵌套关系,上线段树就行了。

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <queue>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
int n,m,q,a[15010];
struct node{
    int mx,se,cnt,lz;
    long long sum;
}tree[60010];
void pushup(int rt){
    tree[rt].sum=tree[lson].sum+tree[rson].sum;
    if(tree[lson].mx>tree[rson].mx){
        tree[rt].mx=tree[lson].mx;
        tree[rt].cnt=tree[lson].cnt;
        tree[rt].se=max(tree[lson].se,tree[rson].mx);
    }
    else if(tree[lson].mx<tree[rson].mx){
        tree[rt].mx=tree[rson].mx;
        tree[rt].cnt=tree[rson].cnt;
        tree[rt].se=max(tree[lson].mx,tree[rson].se);
    }
    else{
        tree[rt].mx=tree[lson].mx;
        tree[rt].cnt=tree[lson].cnt+tree[rson].cnt;
        tree[rt].se=max(tree[lson].se,tree[rson].se);
    }
}
void pushtag(int rt,int val){
    if(val<tree[rt].mx){
        tree[rt].sum-=1ll*(tree[rt].mx-val)*tree[rt].cnt;
        tree[rt].mx=tree[rt].lz=val;
    }
}
void pushdown(int rt){
    if(~tree[rt].lz){
        pushtag(lson,tree[rt].lz);
        pushtag(rson,tree[rt].lz);
        tree[rt].lz=-1;
    }
}
void build(int rt,int l,int r){
    tree[rt].lz=-1;
    if(l==r){
        tree[rt].mx=tree[rt].sum=a[l];
        tree[rt].cnt=1;tree[rt].se=0;return;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);build(rson,mid+1,r);
    pushup(rt);
}
void update(int rt,int L,int R,int l,int r,int val){
    if(val>=tree[rt].mx)return;
    if(l<=L&&R<=r&&tree[rt].se<val){
        pushtag(rt,val);return;
    }
    pushdown(rt);
    int mid=(L+R)>>1;
    if(l<=mid)update(lson,L,mid,l,r,val);
    if(mid<r)update(rson,mid+1,R,l,r,val);
    pushup(rt);
}
long long query(int rt,int L,int R,int l,int r){
    if(l<=L&&R<=r)return tree[rt].sum;
    pushdown(rt);
    int mid=(L+R)>>1;long long val=0;
    if(l<=mid)val+=query(lson,L,mid,l,r);
    if(mid<r)val+=query(rson,mid+1,R,l,r);
    return val;
}
struct Sol{
    int l,r,x;
}s[15010];
struct Ques{
    int l1,r1,l2,r2,id;
    bool operator<(const Ques&s)const{
        return l1<s.l1;
    }
}ques[100010];
vector<Ques>v[100010];
long long ans[100010];
int main(){
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=m;i++)scanf("%d%d%d",&s[i].l,&s[i].r,&s[i].x);
    for(int i=1;i<=q;i++)scanf("%d%d%d%d",&ques[i].l1,&ques[i].r1,&ques[i].l2,&ques[i].r2),ques[i].id=i;
    sort(ques+1,ques+q+1);
    for(int i=1;i<=q;i++){
        for(int j=1;j<=q;j++){
            if(v[j].empty()||ques[i].r1<=v[j].back().r1){
                v[j].push_back(ques[i]);break;
            }
        }
    }
    for(int i=1;i<=q;i++){
        if(v[i].empty())continue;
        build(1,1,n);
        for(int j=v[i].back().l1;j<=v[i].back().r1;j++)update(1,1,n,s[j].l,s[j].r,s[j].x);
        int l=v[i].back().l1,r=v[i].back().r1;
        for(int j=v[i].size()-1;j>=0;j--){
            while(l>v[i][j].l1){
                l--;update(1,1,n,s[l].l,s[l].r,s[l].x);
            }
            while(r<v[i][j].r1){
                r++;update(1,1,n,s[r].l,s[r].r,s[r].x);
            }
            ans[v[i][j].id]=query(1,1,n,v[i][j].l2,v[i][j].r2);
        }
    }
    for(int i=1;i<=q;i++)printf("%lld\n",ans[i]);
    return 0;
}

c

大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办大水题没切怎么办

首先明确答案是 \([x^m]\prod_{i=1}^n(1+xy^{a_i})\) 的 \([0,k)\) 项系数。其中 \(x\) 是加法卷积,\(y\) 是异或卷积。

套路拆 FWT:\([y^w]FWT(1+xy^{a_i})=\begin{cases}1+x,w\otimes a_i=0\\1-x,w\otimes a_i=1\end{cases}\)。那么得到

\[[y^w]FWT\left(\prod_{i=1}^n(1+xy^{a_i})\right)=(1-x)^{cnt_w}(1+x)^{n-cnt_w} \]

其中 \(cnt_w=\sum_{i=1}^nw\otimes a_i\)。

先考虑算 \(cnt_w\)。发现如果对原来的 \(a_i\) 开个桶 FWT 一下那么第 \(w\) 项就是 \(\sum_{i=1}^n[w\oplus a_i=0]-\sum_{i=1}^n[w\oplus a_i=1]\)。然后这两个加起来是 \(n\),解方程就得到 \(cnt_w\)。和黎明前的巧克力那题是一样的。

然后对每个 \(w\) 算 \([x^m](1-x)^w(1+x)^{n-w}\)。暴力拆一下得到它是

\[\begin{aligned} &\sum_{i=0}^m(-1)^i\binom wi\binom{n-w}{m-i}\\ =&w!(n-w)!\sum_{i=0}^m\frac{(-1)^i}{i!(w-i)!}\frac 1{(m-i)!(n-m-(w-i))!} \end{aligned} \]

NTT 算一遍就行了。题解说分治 NTT 好像是可以做的,没细想。

我好菜!

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <set>
using namespace std;
const int mod=998244353;
typedef vector<int> poly;
int n,m,k,b[1<<17];
int wl,w[300010],jc[300010],inv[300010];
void get(int n){wl=1;while(wl<n)wl<<=1;}
#define add(x,y) (x+y>=mod?x+y-mod:x+y)
#define sub(x,y) (x<y?x-y+mod:x-y)
int qpow(int a,int b){
    int ans=1;
    while(b){
        if(b&1)ans=1ll*ans*a%mod;
        a=1ll*a*a%mod;
        b>>=1;
    }
    return ans;
}
void init(int n){
    int t=1;
    while((1<<t)<n)t++;
    t=min(t-1,21);
    w[0]=1;w[1<<t]=qpow(31,1<<21-t);jc[0]=inv[0]=inv[1]=1;
    for(int i=t;i>=1;i--)w[1<<i-1]=1ll*w[1<<i]*w[1<<i]%mod;
    for(int i=1;i<(1<<t);i++)w[i]=1ll*w[i&i-1]*w[i&-i]%mod;
    for(int i=2;i<=n;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    for(int i=1;i<=n;i++)jc[i]=1ll*jc[i-1]*i%mod,inv[i]=1ll*inv[i-1]*inv[i]%mod;
}
inline void DIF(poly &a){
    int n=a.size();
    for(int mid=n>>1;mid;mid>>=1){
        for(int i=0,k=0;i<n;i+=mid<<1,k++){
            for(int j=0;j<mid;j++){
                int x=a[i+j],y=1ll*a[i+j+mid]*w[k]%mod;
                a[i+j]=add(x,y);a[i+j+mid]=sub(x,y);
            }
        }
    }
}
inline void DIT(poly &a){
    int n=a.size();
    for(int mid=1;mid<n;mid<<=1){
        for(int i=0,k=0;i<n;i+=mid<<1,k++){
            for(int j=0;j<mid;j++){
                int x=a[i+j],y=a[i+j+mid];
                a[i+j]=add(x,y);a[i+j+mid]=1ll*sub(x,y)*w[k]%mod;
            }
        }
    }
    for(int i=1;i<=(n-1)>>1;i++)swap(a[i],a[n-i]);
    int inv=qpow(n,mod-2);
    for(int i=0;i<n;i++)a[i]=1ll*a[i]*inv%mod;
}
inline poly operator*(poly a,poly b){
    poly A(a),B(b);
    int n=A.size()+B.size();
    get(n);
    A.resize(wl);B.resize(wl);
    DIF(A);DIF(B);
    for(int i=0;i<wl;i++)A[i]=1ll*A[i]*B[i]%mod;
    DIT(A);A.resize(n-1);
    return A;
}
void fwt(int a[],int n,int tp){
    for(int mid=1;mid<n;mid<<=1){
        for(int i=0;i<n;i+=mid<<1){
            for(int j=0;j<mid;j++){
                int x=a[i+j],y=a[i+j+mid];
                a[i+j]=1ll*tp*(x+y)%mod;
                a[i+j+mid]=1ll*tp*(x-y+mod)%mod;
            }
        }
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&k);init(n<<1);
    for(int i=1;i<=n;i++){
        int x;scanf("%d",&x);b[x]++;
    }
    fwt(b,k,1);
    poly f(n),g(n);
    for(int i=0;i<=m;i++){
        if(i&1)f[i]=1ll*inv[i]*(mod-inv[m-i])%mod;
        else f[i]=1ll*inv[i]*inv[m-i]%mod;
    }
    for(int i=0;i<=n-m;i++)g[i]=1ll*inv[i]*inv[n-m-i]%mod;
    f=f*g;
    for(int i=0;i<k;i++){
        int y=1ll*(n-b[i]+mod)*inv[2]%mod;
        b[i]=1ll*f[y]*jc[y]%mod*jc[n-y]%mod;
    }
    fwt(b,k,inv[2]);
    for(int i=0;i<k;i++)printf("%d ",b[i]);
    return 0;
}

标签:rt,cnt,大水,没切,int,tree,冲刺,清北营
From: https://www.cnblogs.com/gtm1514/p/17359209.html

相关文章

  • 2023程序设计竞赛冲刺③(2019青岛市程序设计竞赛小学组)
    1.取余原题: 解题思路:这道题30%的数据可以开longlong去存储计算,但100%的数据最多有3000位,无法存储,所以可以运用同余的性质,(a*b)%p=(a%p*b%p)%pAC代码:#include<bits/stdc++.h>#definelllonglongusingnamespacestd;constintN=1e3+5,MOD=1e4+7;;lla[N],n,ans......
  • 四级英语冲刺高频500词
    频率一produce:产品likely:stytem:系统activity:活动reward:报酬stress:压力expert:专家concern:涉及关系到university:大学individual:个人的view:视野opportunity:机会hunt:打猎challenge:挑战process:过程,进程project:方案,工程amount:总数ability:能力rate:速率radiation:辐射......
  • 2023冲刺清北营5
    近两日我放过的歌:第一次:花之塔《莉可丽丝》;第二次:前前前世《你的名字》;第三次:心跳《侦探已死》。都是一些动漫中的歌曲,简单征求一下大家对这些歌的评价。(虽然有些番我也没看完)T1吃粮设\(f_i\)表示在\(i\)节点找到狗粮的期望时间,容易发现存在以下转移:\[\begin{aligned}......
  • 冲刺清北营 6
    保龄场。蚌了。场上三道题不是不可做就是不可做,然后跑去做组合。然而昨天看了一晚上多项式\(\gcd\)搞的我现在还在偏头痛。当然也有可能是咖啡因磕多了。题目背景怎么全是龙族。从今天开始戒多项式。万家灯火赛时基本想到正解了,但是我本来打算写的是动态开点线段树……觉得......
  • 团队冲刺总结
    第一阶段十天冲刺圆满结束,回顾这十天的努力,虽然与我们的预定目标有些差距,不过也有了很大成果,以下是我们宿舍对自己的评价:彭锁群:杨凯文:我主要用pyqt5写的前端页面,包括前后端的相结合,我觉得我完成的还比较好,但是就是前端的页面美化部分不太行,都是最基础的页面设计。杨康:在团队中......
  • 团队冲刺总结与绩效
    团队冲刺结束语经过十天,其实是两天的团队项目的第一阶段的冲刺。我们团队白天进行讨论的界面和后台逻辑的处理规划,白天主要是绰进行编写代码大概四到五小时,到了晚上叶接手电脑再敲三四个小时。团队博客一直由叶编写。我们只有一台电脑,绰的电脑坏了,所有我们只能有一个人接手电......
  • 冲刺清北营 5
    尝试了雀巢燃魂,感觉比较偏功能性导致豆似乎不是很好。虽然说咖啡因已经对我没什么太大作用了导致功能性也打折扣。咖啡可能会让你从醒着变成想睡觉,但是绝对不会让你从想睡觉的状态醒过来。等退役了以后有时间写个关于我喝过的咖啡的杂论。参考joke3579的意见是极好的。乌蒙大象......
  • 团队冲刺第九天
    今日完成:协助PC端制作界面,下载并协助pc端初步进行前后端连接       明日目标:协助pc端完成前端后端连接       遇到问题(已解决或未解决):python前后端连接要用到json,因为是前后端分开写的,所以前后端连接时意味着要改一些代码和添加一些代码,这样的工作......
  • 团队冲刺第十天
    今日完成:协助完成前后端连接       明日目标:继续着手安卓端人脸识别       遇到问题(已解决或未解决):明天又回到安卓端,依然是个难点,但我们人手分配更充足了,导入自己项目的问题希望能得到解决......
  • 团队冲刺10
    1.团队成员任务:梁宏凯:今天上课要进行展示我们团队的成果,并且上午进行了一些小问题的修改,修改了通过单个医学文献的“查看详情”功能,可以查看该医学文献中关键信息所在位置的摘要信息,并可进一步查看文献PDF中关键信息所在页的详细内容。王洪兵:进行前后端的连接,将......