6.8 NOI 模拟

\(T1\ edge\)

考虑\(O(q\times n\times \log n)\)的暴力

暴力二分,直接树上差分

#define Eternal_Battle ZXK
#include<bits/stdc++.h>
#define MAXN 50005
using namespace std;
int head[MAXN],nxt[MAXN<<1],to[MAXN<<1],tot;
int dep[MAXN],tag[MAXN],val[MAXN],f[MAXN][22],n,m,q;
struct node
{
    int x,y;
    bool s;
}li[MAXN];
void add(int u,int v)
{
    tot++;
    to[tot]=v;
    nxt[tot]=head[u];
    head[u]=tot;
}
void dfs_pre(int now,int fa)
{
    f[now][0]=fa;
    dep[now]=dep[fa]+1;
    for(int i=1;i<=20;i++)
    {
        f[now][i]=f[f[now][i-1]][i-1];
    }
    for(int i=head[now];i;i=nxt[i])
    {
        int y=to[i];
        if(y==fa) continue;
        dfs_pre(y,now);
    }
}
int LCA(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=20;i>=0;i--)
    {
        if(dep[f[x][i]]>=dep[y]) x=f[x][i];
    }
    if(x==y) return x;
    for(int i=20;i>=0;i--)
    {
        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    }
    return f[x][0];
}
int dfs(int now,int fa)
{
    int res=0;
    for(int i=head[now];i;i=nxt[i])
    {
        int y=to[i];
        if(y==fa) continue;
        res+=dfs(y,now);
    }
    res+=tag[now];
    val[now]=res;
    return res;
}
int lca[3005][3005];
bool check(int x,int r)
{
    memset(val,0,sizeof(val));
    memset(tag,0,sizeof(tag));
    for(int i=x;i<=r;i++)
    {
        if(!li[i].s) continue;
        int u=li[i].x,v=li[i].y;
        tag[u]+=1; tag[v]+=1;
        tag[lca[u][v]]+=-1;
        tag[f[lca[u][v]][0]]+=-1;
    }
    dfs(1,1);
    for(int i=1;i<=n;i++)
    {
        if(!val[i]) return false;
    }
    return true;
}
int sol(int num)
{
    int l=1,r=num,mid,ans=0;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(check(mid,num))
        {
            ans=mid;
            l=mid+1;
        }
        else r=mid-1;
    }
    return ans;
}
int main()
{
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1,u,v;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v); add(v,u);
    }
    dfs_pre(1,0);
    for(int i=1;i<=n;i++)
    {
        for(int j=i;j<=n;j++)
        {
            lca[i][j]=lca[j][i]=LCA(i,j);
        }
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&li[i].x,&li[i].y);
    }
    for(int i=1,r,p,opt;i<=q;i++)
    {
        scanf("%d",&opt);
        if(opt==1)
        {
            scanf("%d",&p);
            li[p].s=true;
        }
        else
        {
            scanf("%d",&r);
            cout<<sol(r)<<"\n";
        }
    }
}

这样是没有前途的

观察数据范围,发现大概可能是个\(O(n\sqrt n \log n)\)

考虑这样一个暴力,从前往后扫,树剖维护链覆盖,取全局最小值即可

考虑区间分块,每个块尾维护一个前缀的树剖,空间复杂度\(O(n\sqrt n)\)

每次修改的话就是,把后面的块都暴力修改一遍,单次复杂度\(O(\sqrt n \log n)\)

查询的话就是找最近的一个块往后移动,查询全局最小值即可,然后\(vector\)撤回操作,单次复杂度\(O(\sqrt n \log n)\)

根据常数大小获得\(60pts\sim 100pts\)

代码,\(std\)

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
const int Maxn=50000;
const int Maxq=100000;
const int Maxb=1500;
const int Maxv=(Maxn-1)/Maxb+1;
const int Inf=0x3f3f3f3f;
int n,m,q;
struct Edge{
    int u,v;
}edge[Maxn+5];
bool vis_op[Maxn+5];
int op_id[Maxq+5];
int ans[Maxq+5];
int find_belong(int x){
    return (x-1)/Maxb+1;
}
int find_bel_l(int x){
    return (x-1)*Maxb+1;
}
int find_bel_r(int x){
    return std::min(m,x*Maxb);
}
int head[Maxn+5],arrive[Maxn<<1|5],nxt[Maxn<<1|5],tot;
void add_edge(int from,int to){
    arrive[++tot]=to;
    nxt[tot]=head[from];
    head[from]=tot;
}
int fa[Maxn+5],sz[Maxn+5],son[Maxn+5],dep[Maxn+5],top[Maxn+5];
int dfn[Maxn+5],rnk[Maxn+5],dfn_tot;
void init_dfs_1(int u){
    sz[u]=1;
    dep[u]=dep[fa[u]]+1;
    for(int i=head[u];i;i=nxt[i]){
        int v=arrive[i];
        if(v==fa[u]){
            continue;
        }
        fa[v]=u;
        init_dfs_1(v);
        sz[u]+=sz[v];
        if(son[u]==0||sz[v]>sz[son[u]]){
            son[u]=v;
        }
    }
}
void init_dfs_2(int u,int tp){
    dfn[u]=++dfn_tot;
    rnk[dfn[u]]=u;
    top[u]=tp;
    if(son[u]){
        init_dfs_2(son[u],tp);
    }
    for(int i=head[u];i;i=nxt[i]){
        int v=arrive[i];
        if(v==fa[u]||v==son[u]){
            continue;
        }
        init_dfs_2(v,v);
    }
}
int find_lca(int u,int v){
    while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]]){
            std::swap(u,v);
        }
        u=fa[top[u]];
    }
    return dep[u]<dep[v]?u:v;
}
bool vis[Maxn+5];
int vis_up[Maxn+5],vis_down[Maxn+5];
bool on_path[Maxn+5];
void vir_dfs_1(int u){
    if(vis[u]){
        vis_up[u]=vis_down[u]=u;
    }
    else{
        vis_up[u]=vis_up[fa[u]];
    }
    int num_son=0;
    for(int i=head[u];i;i=nxt[i]){
        int v=arrive[i];
        if(v==fa[u]){
            continue;
        }
        vir_dfs_1(v);
        if(vis_down[v]&&!vis[u]){
            num_son++;
            vis_down[u]=vis_down[v];
        }
    }
    if(!vis[u]&&num_son>1){
        vis[u]=1;
        vis_up[u]=vis_down[u]=u;
    }
}
void vir_dfs_2(int u){
    if(vis_up[u]&&vis_down[u]){
        on_path[u]=1;
        if(!vis[u]){
            vis_up[u]=vis_up[fa[u]];
        }
    }
    else{
        if(on_path[fa[u]]){
            vis_up[u]=fa[u];
        }
        else{
            vis_up[u]=vis_up[fa[u]];
        }
    }
    for(int i=head[u];i;i=nxt[i]){
        int v=arrive[i];
        if(v==fa[u]){
            continue;
        }
        vir_dfs_2(v);
    }
}
namespace Subtask_1{
    int val_num[Maxn+5],val_pos;
    struct Node{
        int ch[2];
        int dep_l,dep_r;
        int cur_val,mn_val,lazy;
    }node[Maxn+5];
    int lis[Maxn+5],sum[Maxn+5],root[Maxn+5],mn_n[Maxn+5];
    int len;
    int build_line(int l,int r){
        if(l>r){
            return 0;
        }
        int left=l,right=r;
        while(left<right){
            int mid=(left+right)/2;
            if(sum[mid]-sum[l-1]<sum[r]-sum[mid]){
                left=mid+1;
            }
            else{
                right=mid;
            }
        }
        int root=lis[left];
        node[root].dep_l=dep[lis[l]],node[root].dep_r=dep[lis[r]];
        node[root].ch[0]=build_line(l,left-1);
        node[root].ch[1]=build_line(left+1,r);
        node[root].cur_val=node[root].mn_val=node[root].lazy=0;
        return root;
    }
    void build_tree(int u){
        int lst_fa=fa[u];
        fa[u]=0;
        auto get_line=[&](int x){
            len=0;
            while(fa[x]&&son[fa[x]]==x){
                lis[++len]=x;
                x=fa[x];
            }
            lis[++len]=x;
            std::reverse(lis+1,lis+1+len);
            for(int i=1;i<=len;i++){
                sum[i]=sum[i-1]+sz[lis[i]]-sz[son[lis[i]]];
            }
            int r=build_line(1,len);
            for(int i=1;i<=len;i++){
                root[lis[i]]=r;
                mn_n[lis[i]]=x;
            }
            val_num[node[r].mn_val]++;
        };
        for(int i=dfn[u];i<dfn[u]+sz[u];i++){
            int v=rnk[i];
            if(son[v]==0){
                get_line(v);
            }
        }
        fa[u]=lst_fa;
    }
    void update_tag(int root,int a){
        node[root].cur_val=std::max(node[root].cur_val,a),node[root].mn_val=std::max(node[root].mn_val,a),node[root].lazy=std::max(node[root].lazy,a);
    }
    void push_up(int root){
        node[root].mn_val=std::max(std::min(node[root].cur_val,std::min(node[node[root].ch[0]].mn_val,node[node[root].ch[1]].mn_val)),node[root].lazy);
    }
    void _update(int root,int l,int r,int val){
        if(root==0||r<node[root].dep_l||l>node[root].dep_r||l>r||val<=node[root].lazy){
            return;
        }
        if(l<=node[root].dep_l&&r>=node[root].dep_r){
            update_tag(root,val);
            return;
        }
        if(l<=dep[root]&&r>=dep[root]){
            node[root].cur_val=std::max(node[root].cur_val,val);
        }
        _update(node[root].ch[0],l,r,val),_update(node[root].ch[1],l,r,val);
        push_up(root);
    }
    void update(int root,int l,int r,int val){
        val_num[node[root].mn_val]--;
        _update(root,l,r,val);
        val_num[node[root].mn_val]++;
        while(val_pos<=m&&val_num[val_pos]==0){
            val_pos++;
        }
    }
    void modify_root(int u,int val){
        while(mn_n[u]){
            update(root[u],dep[mn_n[u]],dep[u],val);
            u=fa[mn_n[u]];
        }
    }
    void modify_path(int u,int v,int val){
        while(mn_n[u]!=mn_n[v]){
            if(dep[mn_n[u]]<dep[mn_n[v]]){
                std::swap(u,v);
            }
            update(root[u],dep[mn_n[u]],dep[u],val);
            u=fa[mn_n[u]];
        }
        if(dep[u]>dep[v]){
            std::swap(u,v);
        }
        update(root[u],dep[u]+1,dep[v],val);
    }
    void init_dfs(int u){
        if(vis_down[u]==0){
            build_tree(u);
            return;
        }
        for(int i=head[u];i;i=nxt[i]){
            int v=arrive[i];
            if(v==fa[u]){
                continue;
            }
            init_dfs(v);
        }
    }
    void init(){
        for(int i=1;i<=n;i++){
            mn_n[i]=0;
        }
        node[0].mn_val=Inf;
        val_pos=0;
        for(int i=0;i<=m;i++){
            val_num[i]=0;
        }
        init_dfs(1);
        while(val_pos<=m&&val_num[val_pos]==0){
            val_pos++;
        }
    }
}
namespace Subtask_2{
    struct Segment_Tree{
        int n;
        std::vector<int> val;
        void init(int _n){
            n=_n;
            val.clear();
            val.resize(n*2+2);
            val[n*2]=Inf;
        }
        void update(int l,int r,int a){
            if(l>r){
                return;
            }
            int s_l=l+n-1,s_r=r+n-1;
            for(l+=n-1,r+=n;l<r;l>>=1,r>>=1){
                if(l&1){
                    val[l]=std::max(val[l],a);
                    l++;
                }
                if(r&1){
                    r--;
                    val[r]=std::max(val[r],a);
                }
                val[l>>1]=std::max(val[l>>1],std::min(val[l],val[l^1]));
                val[r>>1]=std::max(val[r>>1],std::min(val[r],val[r^1]));
            }
            for(;s_l>1;s_l>>=1){
                val[s_l>>1]=std::max(val[s_l>>1],std::min(val[s_l],val[s_l^1]));
            }
            for(;s_r>1;s_r>>=1){
                val[s_r>>1]=std::max(val[s_r>>1],std::min(val[s_r],val[s_r^1]));
            }
        }
        int query(){
            int ans=Inf;
            for(int l=n,r=n*2;l<r;l>>=1,r>>=1){
                if(l&1){
                    ans=std::min(ans,val[l++]);
                }
                if(r&1){
                    ans=std::min(ans,val[--r]);
                }
            }
            return ans;
        }
    }seg[Maxb<<1|5];
    int seg_id[Maxn+5];
    int seg_id_tot;
    void init_dfs(int u){
        if(vis_down[u]==0){
            return;
        }
        if(vis[u]&&fa[u]){
            seg_id[u]=++seg_id_tot;
            seg[seg_id[u]].init(dep[u]-dep[vis_up[fa[u]]]);
        }
        for(int i=head[u];i;i=nxt[i]){
            int v=arrive[i];
            if(v==fa[u]){
                continue;
            }
            init_dfs(v);
        }
    }
    void init(){
        seg_id_tot=0;
        init_dfs(1);
    }
    void modify_path(int u,int v,int val){
        if(dep[u]>dep[v]){
            std::swap(u,v);
        }
        int pos=vis_down[v];
        seg[seg_id[pos]].update(dep[u]-dep[vis_up[fa[pos]]]+1,dep[v]-dep[vis_up[fa[pos]]],val);
    }
    int query_path(int u){
        return seg[seg_id[vis_down[u]]].query();
    }
}
namespace Subtask_3{
    struct Node{
        int ch[2];
        int dep_l,dep_r;
        int cur_val,lazy;
    }node[Maxb<<1|5];
    int sz[Maxb<<1|5],fa[Maxb<<1|5],dep[Maxb<<1|5],son[Maxb<<1|5],top[Maxb<<1|5],mn_r[Maxb<<1|5];
    std::vector<int> g[Maxb<<1|5];
    int re_id[Maxn+5],re_id_tot;
    void init_dfs_1(int u){
        dep[u]=dep[fa[u]]+1;
        sz[u]=1;
        son[u]=0;
        for(int v:g[u]){
            fa[v]=u;
            init_dfs_1(v);
            sz[u]+=sz[v];
            if(son[u]==0||sz[v]>sz[son[u]]){
                son[u]=v;
            }
        }
    }
    int lis[Maxb<<1|5],len;
    int sum_sz[Maxb<<1|5];
    int build_line(int l,int r){
        if(l>r){
            return 0;
        }
        int left=l,right=r;
        while(left<right){
            int mid=(left+right)/2;
            if(sum_sz[mid]-sum_sz[l-1]<sum_sz[r]-sum_sz[mid]){
                left=mid+1;
            }
            else{
                right=mid;
            }
        }
        int root=lis[left];
        node[root].dep_l=dep[lis[l]],node[root].dep_r=dep[lis[r]];
        node[root].ch[0]=build_line(l,left-1);
        node[root].ch[1]=build_line(left+1,r);
        node[root].cur_val=node[root].lazy=0;
        return root;
    }
    void build_tree(){
        for(int i=1;i<=len;i++){
            sum_sz[i]=sum_sz[i-1]+sz[lis[i]]-sz[son[lis[i]]];
        }
        int root=build_line(1,len);
        for(int i=1;i<=len;i++){
            mn_r[lis[i]]=root;
        }
    }
    void init_dfs_2(int u,int tp){
        top[u]=tp;
        lis[++len]=u;
        if(son[u]){
            init_dfs_2(son[u],tp);
        }
        else{
            build_tree();
            len=0;
        }
        for(int v:g[u]){
            if(v==son[u]){
                continue;
            }
            init_dfs_2(v,v);
        }
    }
    void update_tag(int root,int a){
        node[root].cur_val=std::max(node[root].cur_val,a),node[root].lazy=std::max(node[root].lazy,a);
    }
    void update(int root,int l,int r,int val){
        if(root==0||r<node[root].dep_l||l>node[root].dep_r||val<=node[root].lazy){
            return;
        }
        if(l<=node[root].dep_l&&r>=node[root].dep_r){
            update_tag(root,val);
            return;
        }
        if(l<=dep[root]&&r>=dep[root]){
            node[root].cur_val=std::max(node[root].cur_val,val);
        }
        update(node[root].ch[0],l,r,val),update(node[root].ch[1],l,r,val);
    }
    void modify_path(int u,int v,int val){
        int num=0;
        u=re_id[u],v=re_id[v];
        while(top[u]!=top[v]){
            if(dep[top[u]]<dep[top[v]]){
                std::swap(u,v);
            }
            num++;
            update(mn_r[u],dep[top[u]],dep[u],val);
            u=fa[top[u]];
        }
        if(dep[u]>dep[v]){
            std::swap(u,v);
        }
        num++;
        update(mn_r[u],dep[u]+1,dep[v],val);
        // fprintf(stderr,"%d %d\n",re_id_tot,num);
    }
    void _push_down(int root,int val=0){
        if(root==0){
            return;
        }
        val=std::max(val,node[root].lazy);
        node[root].lazy=val;
        node[root].cur_val=std::max(node[root].cur_val,val);
        _push_down(node[root].ch[0],val),_push_down(node[root].ch[1],val);
    }
    void push_down(){
        for(int i=1;i<=re_id_tot;i++){
            if(top[i]==i){
                _push_down(mn_r[i]);
            }
        }
    }
    void init(){
        for(int i=1;i<=re_id_tot;i++){
            fa[i]=0,g[i].clear();
        }
        re_id_tot=0;
        for(int i=1;i<=n;i++){
            if(vis[i]){
                re_id[i]=++re_id_tot;
            }
        }
        for(int i=1;i<=n;i++){
            if(vis[i]){
                if(::fa[i]){
                    g[re_id[vis_up[::fa[i]]]].push_back(re_id[i]);
                }
            }
        }
        init_dfs_1(1);
        init_dfs_2(1,1);
    }
    namespace DSU{
        int num;
        int fa[Maxb<<1|5];
        void init(){
            num=re_id_tot;
            for(int i=1;i<=re_id_tot;i++){
                fa[i]=i;
            }
        }
        int find(int x){
            if(x==fa[x]){
                return x;
            }
            return fa[x]=find(fa[x]);
        }
        void merge(int x,int y){
            int fa_x=find(x),fa_y=find(y);
            if(fa_x==fa_y){
                return;
            }
            fa[fa_y]=fa_x;
            num--;
        }
    }
    void merge_path(int u,int v){
        while(u!=v){
            if(dep[u]<dep[v]){
                std::swap(u,v);
            }
            DSU::merge(fa[u],u);
            u=DSU::find(u);
        }
    }
    int query(int l,int r){
        DSU::init();
        for(int i=r;i>=l;i--){
            if(!vis_op[i]){
                continue;
            }
            int cur_u=re_id[edge[i].u],cur_v=re_id[edge[i].v];
            merge_path(cur_u,cur_v);
            if(DSU::num==1){
                return i;
            }
        }
        push_down();
        int ans=Inf;
        for(int i=2;i<=re_id_tot;i++){
            if(DSU::find(i)==i){
                ans=std::min(ans,node[i].cur_val);
            }
        }
        return ans;
    }
}
void change_path(int u,int v,int val){
    if(u==v){
        return;
    }
    Subtask_2::modify_path(u,v,val);
    Subtask_3::modify_path(vis_up[fa[v]],vis_down[v],Subtask_2::query_path(v));
}
void _update_path(int u,int fa,int val){
    if(u==fa){
        return;
    }
    if(!on_path[fa]){
        Subtask_1::modify_path(u,fa,val);
    }
    else if(on_path[u]){
        if(vis_up[::fa[u]]==vis_up[fa]){
            change_path(fa,u,val);
        }
        else{
            change_path(fa,vis_down[fa],val);
            change_path(vis_up[::fa[u]],u,val);
            Subtask_3::modify_path(vis_down[fa],vis_up[::fa[u]],val);
        }
    }
    else{
        Subtask_1::modify_root(u,val);
        u=vis_up[u];
        _update_path(u,fa,val);
    }
}
void update_path(int u,int v,int val){
    int lca=find_lca(u,v);
    _update_path(u,lca,val),_update_path(v,lca,val);
}
int query(int bel_l,int r){
    return std::min(Subtask_1::val_pos,Subtask_3::query(bel_l,r));
}
namespace Init{
    int head[Maxn+5],arrive[Maxn<<1|5],nxt[Maxn<<1|5],tot;
    void add_edge(int from,int to){
        arrive[++tot]=to;
        nxt[tot]=head[from];
        head[from]=tot;
    }
    int dfn[Maxn+5],dfn_tot;
    void init_dfs(int u,int fa){
        dfn[u]=++dfn_tot;
        for(int i=head[u];i;i=nxt[i]){
            int v=arrive[i];
            if(v==fa){
                continue;
            }
            init_dfs(v,u);
            ::add_edge(dfn[u],dfn[v]);
        }
    }
    void init(){
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v),add_edge(v,u);
        }
        init_dfs(1,0);
    }
}
int qry_num[Maxn+5];
int main(){
 
    scanf("%d%d%d",&n,&m,&q);
    Init::init();
    /*for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        add_edge(u,v),add_edge(v,u);
    }*/
    for(int i=1;i<=m;i++){
        scanf("%d%d",&edge[i].u,&edge[i].v);
        edge[i].u=Init::dfn[edge[i].u],edge[i].v=Init::dfn[edge[i].v];
    }
    for(int i=1;i<=q;i++){
        int op;
        scanf("%d%d",&op,&op_id[i]);
        if(op==2){
            qry_num[op_id[i]]++;
            op_id[i]=-op_id[i];
        }
    }
    init_dfs_1(1);
    init_dfs_2(1,1);
    for(int l=1,r;l<=m;l=r){
        r=l;
        memset(vis_up,0,sizeof vis_up),memset(vis_down,0,sizeof vis_down),memset(vis,0,sizeof vis),memset(on_path,0,sizeof on_path),memset(vis_op,0,sizeof vis_op);
        vis[1]=1;
        int num=1;
        while(r<=m){
            num+=(!vis[edge[r].u])+(!vis[edge[r].v])+qry_num[r];
            vis[edge[r].u]=vis[edge[r].v]=1;
            r++;
            if(num>Maxb){
                break;
            }
        }
        vir_dfs_1(1),vir_dfs_2(1);
        Subtask_1::init();
        Subtask_2::init();
        Subtask_3::init();
        std::vector<int> cur_q;
        for(int j=1;j<=q;j++){
            if(op_id[j]<0){
                std::sort(cur_q.begin(),cur_q.end(),[](int p,int q){return p>q;});
                for(int k:cur_q){
                    update_path(edge[k].u,edge[k].v,k);
                }
                cur_q.clear();
                if(l<=-op_id[j]&&-op_id[j]<=r){
                    ans[j]=query(l,-op_id[j]);
                }
            }
            else{
                if(op_id[j]<l){
                    cur_q.push_back(op_id[j]);
                }
                vis_op[op_id[j]]=1;
            }
        }
    }
    for(int i=1;i<=q;i++){
        if(op_id[i]<0){
            printf("%d\n",ans[i]);
        }
    }
    return 0;
}

\(T2\ zero\)

我们可以推出来第一步

考虑一下生成函数

\[F_k=F_{k-1}+x F_k + x^2F_k \\ (1-x-x^2)F_k=F_{k-1} \\ F_k=\frac{F_{k-1}}{1-x-x^2} \\ F_k=\frac{F_1}{(1-x-x^2)^{k-1}} \\ F_k=\frac{1}{(1-x-x^2)^{k}} \]

\(F_0\)是原始的斐波那契数列

我们要求\(F_k\)的第\(n\)项,\(n<=1\times 10^{100000}\)

这个暴力多项式计算的话,会寄,可以拿到\(1pts\)

这个常系数线性齐次递推的话,会寄,可以拿到\(1pts\)

这个暴力递推的话,不会寄。。。

考虑继续推式子

\[[x^n]\frac{1}{(1-x-x^2)^k} \\ \lambda_1=\frac{1+\sqrt 5}{2}\ \ \ \ \ \lambda_2=\frac{1-\sqrt 5}{2} \\ [x^n]\frac{1}{(1-\lambda_1 x)^k}\frac{1}{(1-\lambda_2 x)^k} \]

考虑初始形态

\[\frac{1}{1-x}=1+x+x^2+x^3... \\ [x^n]\frac{1}{(1-x)^k}=\binom{n+k-1}{k-1} \]

首先设

\[K=k-1 \\ q=\frac{\lambda_1}{\lambda_2} \\ C=\frac{\lambda_2^n (-1)^K}{(K!)^2} \]

然后

\[\sum_{i=0}^n\binom{i+K}{K}\binom{n-i+K}{K}\lambda_1^i\lambda_2^{n-i} \\ \frac{\lambda_2^n}{(K!)^2}\sum_{i=0}^n(i+K)^{\underline{K}}(n-i+K)^{\underline{K}}q^i \\ C\sum_{i=0}^n (i+K)^{\underline{K}}(i-n-1)^{\underline{K}}q^i \\ C\sum_{i=0}^n(i+K)^{\underline{K}}q^i\sum_{j=0}^K\binom{K}{j} i^j(-n-1)^{K-j} \\ C\sum_{j=0}^K\binom{K}{j}(-n-1)^{\underline{K-j}}\sum_{i=0}^n(i+K)^{\underline{K+j}}q^i \]

前半部分可以做到\(O(k)\),考虑后半部分如何线性预处理

\[S_p=\sum_{i=0}^n(i+K)^{\underline{p}}q^i \\ \sum_{i=0}^n (i+K-1)^{\underline{p}}q^i+p(i+K-1)^{\underline{p-1}}q^i \\ q\times S_p-q^{n+1}(n+K)^{\underline{p}}+(K-1)^\underline{p}+p(q\times S_{p-1}-q^{n+1}(n+K)^{\underline{p-1}}+(K-1)^\underline{p-1}) \]

也可以\(O(k)\)得到

#include<bits/stdc++.h>
#define N 10000000
#define int long long
#define mode 469762049
using namespace std;
int poww(int x,int y)
{
    int su=1;
    while(y)
    {
        if(y&1) 
        {
            su=su*x%mode;
        }
        x=x*x%mode;
        y>>=1;
    }
    return su;
}
const int lam1=poww(6922763,mode-2),lam2=poww(462839285,mode-2),q=lam1*poww(lam2,mode-2)%mode,inq=poww(q,mode-2);
int inv(int x)
{
    return poww(x,mode-2);
}
int k,n,nn,jc[N+10],invs[N+10],f[N*2+10];
char s[N];
signed main()
{
    jc[0]=1;
    for(int i=1;i<=N;++i) jc[i]=jc[i-1]*i%mode;
    invs[N]=inv(jc[N]);
    for(int i=N-1;i>=0;--i) invs[i]=invs[i+1]*(i+1)%mode;
    cin>>k>>s+1;
    int l=strlen(s+1);
    for(int i=1;i<=l;++i)
    {
        n=(n*10+s[i]-'0')%mode;
        nn=(nn*10+s[i]-'0')%(mode-1);
    }
    int f1=mode-poww(q,nn+1),f2=1,v1=(n+k-1)%mode,v2=(k-2+mode)%mode,iv=inv(mode+1-q);
    f[0]=iv*(f1+1)%mode;
    for(int i=1;i<=2*k;++i)
    {
        f[i]=i*((q*f[i-1]%mode+f1+f2)%mode)%mode;
        f1=f1*(v1--)%mode;
        f2=f2*(v2--)%mode;
        f[i]=(f[i]+f1+f2)*iv%mode;
    }
    int cf=poww(lam2,nn)*invs[k-1]%mode*invs[k-1]%mode;
    if(k%2==0) cf=(mode-cf)%mode;
    int ans=0,v=mode-n-1,ff=1;
    for(int i=k-1;i>=0;--i)
    {
        int p=jc[k-1]*invs[i]%mode*invs[k-1-i]%mode*ff%mode;
        ans=(ans+p*f[k-1+i]%mode)%mode;
        ff=ff*(v--)%mode;
    }
    ans=ans*cf%mode;
    cout<<ans<<endl;
}

\(T3\ diana\)

首先容易想到式子

\[\varphi(a\times b)=\frac{\varphi(a)\varphi(b)\gcd(a,b)}{\varphi(\gcd(a,b))} \]

维护区间最大值,由于后面的\(\frac{\gcd(a,b)}{\varphi(gcd(a,b))}\)不好处理,那么就枚举这一部分

我们枚举\(\gcd\),拿出所有\(\gcd\)的倍数,按照\(\frac{\varphi(a)\varphi(b)\varphi(\gcd)}{\gcd}\)去计算,这样算即使部分不是正确的,但算出的结果会\(\leq\)真实结果

我们可以暴力枚举\(\gcd\),暴力统计,复杂度\(O(q\times n\times \ln (n))\)

考虑 \(q\) 很大而 \(n\) 很小,我们枚举 \(\gcd\) 记三元组 \((i,j,val)\),然后扫描线一下即可

这个时候的问题是,\(n\) 大的时候,三元组个数会很多

\(\gcd\) 确定时大小只和 \(\varphi(p_i)\)\(\varphi(p_j)\) 有关,考虑枚举两者之间的较小值

结论:答案只可能是距离 \(i\) 最近的并且 \(\varphi(p_j)>\varphi(p_i)\) 的左右两值

证明:考虑\(\varphi(p_k)>\varphi(p_j)>\varphi(p_i),k<j<i\)\(i\)\(k\) 匹配一定不比 \(j\)\(k\) 匹配更优

然后现在三元组数量控制在 \(O(n\ln n)\)就可以愉快扫描线了

\(45pts\)线段树惨遭卡常代码

#include<bits/stdc++.h>
#define int long long
#define MAXN 500005
using namespace std;
struct node
{
	int l,r,id,val;
}li[MAXN<<5];
int Ans[MAXN];
template<class T>
T Read()
{
	T x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')
		f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}
int (*read)()=Read<int>;
#define read Read<int>
namespace Seg
{
	 #define ls (now<<1)
	 #define rs ((now<<1)|1)
     struct Tree
     {
     	 int l,r,Max;
	 }tr[MAXN<<4];
	 void build(int now,int l,int r)
	 {
	 	  tr[now].l=l;
	 	  tr[now].r=r;
	 	  if(l==r) return ;
	      int mid=(l+r)>>1;
	      build(ls,l,mid);
	      build(rs,mid+1,r);
	 }
	 void push_up(int now)
	 {
	     tr[now].Max=max(tr[ls].Max,tr[rs].Max);	
	 }
	 void change(int now,int poz,int k)
	 {
	 	if(tr[now].l==poz&&tr[now].r==poz)
	 	{
	 	   tr[now].Max=max(tr[now].Max,k);
	 	   return;
		}
		int mid=(tr[now].l+tr[now].r)>>1;
		if(poz<=mid) change(ls,poz,k);
		else change(rs,poz,k);
		push_up(now);
	 }
	 int query(int now,int l,int r)
	 {
	 	 if(tr[now].l>=l&&tr[now].r<=r)
	 	 {
	 	    return tr[now].Max;	
		 }
		 int mid=(tr[now].l+tr[now].r)>>1;
		 int res=0;
		 if(l<=mid) res=max(res,query(ls,l,r));
		 if(r>mid)  res=max(res,query(rs,l,r));
		 return res;
	 }
}
bool vis[MAXN+5];
int pri[MAXN+5],phi[MAXN+5],sta[MAXN],poz[MAXN],p[MAXN],num,cnt,q,n;
void Init()
{
	phi[1]=1;
	for(int i=2;i<=MAXN;i++)
	{
		if(!vis[i]) 
		{
			pri[++num]=i;
			phi[i]=i-1;
		}
		for(int j=1;j<=num&&i*pri[j]<=MAXN;j++)
		{
		    int now=i*pri[j];
		    vis[now]=true;
			if(i%pri[j]==0)
			{
			   phi[now]=phi[i]*pri[j];
			   break;
			}
			phi[now]=phi[i]*(pri[j]-1);
		}
	}
}
inline void Print(int x){
    static char tmp[250];
    if(x == 0) putchar('0');
    int t = 0;
    while(x) tmp[++t] = x % 10 + '0' , x /= 10;
    while(t) putchar(tmp[t]) , t--;
    putchar('\n');
}
signed main()
{
	Init();
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		p[i]=read();
		poz[p[i]]=i;
	}
//	cout<<"line:\n";
//    for(int i=1;i<=n;i++) cout<<phi[p[i]]<<" ";
	for(int G=1;G<=n;G++)
	{
		vector<pair<int,int> >Mid;
		for(int i=G;i<=n;i+=G)
		{
			Mid.push_back(make_pair(poz[i],phi[i]));
		}
		sort(Mid.begin(),Mid.end());
		int top=0;
		for(int i=0;i<Mid.size();i++)
		{
			while(top&&Mid[sta[top]].second<=Mid[i].second) 
			{
				++cnt;
				li[cnt].l=Mid[sta[top]].first;
				li[cnt].r=Mid[i].first;
				li[cnt].val=Mid[sta[top]].second*Mid[i].second*G/phi[G];
				top--;
			}
			sta[++top]=i;
		}
		top=0;
		for(int i=Mid.size()-1;i>=0;i--)
		{
			while(top&&Mid[sta[top]].second<=Mid[i].second)
			{
				++cnt;
//				cout<<M
				li[cnt].l=Mid[i].first;
				li[cnt].r=Mid[sta[top]].first;
				li[cnt].val=Mid[i].second*Mid[sta[top]].second*G/phi[G];
				top--;
			}
			sta[++top]=i;
		}
	}
	scanf("%lld",&q);
	for(int i=1;i<=q;i++)
	{
		++cnt;
		li[cnt].id=i;
		li[cnt].l=read();
		li[cnt].r=read();
	}
	Seg::build(1,1,n);
	sort(li+1,li+1+cnt,[=](node a,node b){if(a.r==b.r) return a.id<b.id;return a.r<b.r;});
	for(int i=1;i<=cnt;i++)
	{
		if(li[i].id)
		{
			Ans[li[i].id]=Seg::query(1,li[i].l,li[i].r);
		}
		else
		{
			Seg::change(1,li[i].l,li[i].val);
		}
	}
	for(int i=1;i<=q;i++)
	{
		Print(Ans[i]);
	}
}

不得不写成树状数组

/*
如果写线段树的话,建议写zkw 
亲身验证普通线段树只能45pts 
*/
#include<bits/stdc++.h>
#define int long long
#define MAXN 500005
using namespace std;
struct node
{
    int l,r,id,val;
}li[MAXN<<5];
int Ans[MAXN];
template<class T>
T Read()
{
    T x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
        f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<1)+(x<<3)+(ch^'0');
        ch=getchar();
    }
    return x*f;
}
int (*read)()=Read<int>;
#define read Read<int>
bool vis[MAXN+5];
int pri[MAXN+5],phi[MAXN+5],sta[MAXN],poz[MAXN],p[MAXN],num,cnt,q,n;
namespace Seg
{
     int tr[MAXN];
     int lowbit(int x)
     {
         return x&(-x);
     }
     void Insert(int x,int k)
     {
          while(x) tr[x]=max(tr[x],k),x-=lowbit(x);
     }
     int Query(int x)
     {
         int res=0;
         while(x<=n) res=max(res,tr[x]),x+=lowbit(x);
         return res;
     }
//   #define ls (now<<1)
//   #define rs ((now<<1)|1)
//     struct Tree
//     {
//       int l,r,Max;
//   }tr[MAXN<<4];
//   void build(int now,int l,int r)
//   {
//        tr[now].l=l;
//        tr[now].r=r;
//        if(l==r) return ;
//        int mid=(l+r)>>1;
//        build(ls,l,mid);
//        build(rs,mid+1,r);
//   }
//   void push_up(int now)
//   {
//       tr[now].Max=max(tr[ls].Max,tr[rs].Max);    
//   }
//   void change(int now,int poz,int k)
//   {
//      if(tr[now].l==poz&&tr[now].r==poz)
//      {
//         tr[now].Max=max(tr[now].Max,k);
//         return;
//      }
//      int mid=(tr[now].l+tr[now].r)>>1;
//      if(poz<=mid) change(ls,poz,k);
//      else change(rs,poz,k);
//      push_up(now);
//   }
//   int query(int now,int l,int r)
//   {
//       if(tr[now].l>=l&&tr[now].r<=r)
//       {
//          return tr[now].Max; 
//       }
//       int mid=(tr[now].l+tr[now].r)>>1;
//       int res=0;
//       if(l<=mid) res=max(res,query(ls,l,r));
//       if(r>mid)  res=max(res,query(rs,l,r));
//       return res;
//   }
}
 
void Init()
{
    phi[1]=1;
    for(int i=2;i<=MAXN;i++)
    {
        if(!vis[i]) 
        {
            pri[++num]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=num&&i*pri[j]<=MAXN;j++)
        {
            int now=i*pri[j];
            vis[now]=true;
            if(i%pri[j]==0)
            {
               phi[now]=phi[i]*pri[j];
               break;
            }
            phi[now]=phi[i]*(pri[j]-1);
        }
    }
}
inline void Print(int x)
{
    static char tmp[250];
    if(x == 0) putchar('0');
    int t = 0;
    while(x) tmp[++t] = x % 10 + '0' , x /= 10;
    while(t) putchar(tmp[t]) , t--;
    putchar('\n');
}
signed main()
{
    Init();
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        p[i]=read();
        poz[p[i]]=i;
    }
//  cout<<"line:\n";
//    for(int i=1;i<=n;i++) cout<<phi[p[i]]<<" ";
    for(int G=1;G<=n;G++)
    {
        vector<pair<int,int> >Mid;
        for(int i=G;i<=n;i+=G)
        {
            Mid.push_back(make_pair(poz[i],phi[i]));
        }
        sort(Mid.begin(),Mid.end());
        int top=0;
        for(int i=0;i<Mid.size();i++)
        {
            while(top&&Mid[sta[top]].second<=Mid[i].second) 
            {
                ++cnt;
                li[cnt].l=Mid[sta[top]].first;
                li[cnt].r=Mid[i].first;
                li[cnt].val=Mid[sta[top]].second*Mid[i].second*G/phi[G];
                top--;
            }
            sta[++top]=i;
        }
        top=0;
        for(int i=Mid.size()-1;i>=0;i--)
        {
            while(top&&Mid[sta[top]].second<=Mid[i].second)
            {
                ++cnt;
//              cout<<M
                li[cnt].l=Mid[i].first;
                li[cnt].r=Mid[sta[top]].first;
                li[cnt].val=Mid[i].second*Mid[sta[top]].second*G/phi[G];
                top--;
            }
            sta[++top]=i;
        }
    }
    scanf("%lld",&q);
    for(int i=1;i<=q;i++)
    {
        ++cnt;
        li[cnt].id=i;
        li[cnt].l=read();
        li[cnt].r=read();
    }
    sort(li+1,li+1+cnt,[=](node a,node b){if(a.r==b.r) return a.id<b.id;return a.r<b.r;});
    for(int i=1;i<=cnt;i++)
    {
        if(li[i].id)
        {
            Ans[li[i].id]=Seg::Query(li[i].l);
        }
        else
        {
            Seg::Insert(li[i].l,li[i].val);
        }
    }
    for(int i=1;i<=q;i++)
    {
        Print(Ans[i]);
    }
}
posted @ 2022-06-08 21:10  Authentic_k  阅读(41)  评论(0编辑  收藏  举报