• 11月11日考试 题解(exgcd+树形DP+模拟+最短路+哈希+主席树)


    T1 方程的解

    题目大意:求$ax+by=c$的正整数解的个数。

    exgcd板子。求出来$x$取得最小正整数解时$y$的解;再求出$y$的最小正整数解。两者之差除以$frac{a}{gcd (a,b)}$加一即为答案。注意细节。

    代码:

    #include<cstdio>
    #include<iostream>
    #define int long long
    using namespace std;
    int T,a,b,c,x,y,d;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f; 
    }
    inline void exgcd(int a,int b,int c,int &x,int &y,int &d)
    {
        if(!b) y=0,d=a,x=c/a;
        else  exgcd(b,a%b,c,y,x,d),y-=(a/b)*x;
    }
    signed main()
    {
        T=read();
        while(T--)
        {
            a=read(),b=read(),c=read();
            if (!a&&!b)
            {
                if (!c) puts("ZenMeZheMeDuo");
                else puts("0");
                continue;
            }
            if (c<0) a=-a,b=-b,c=-c;
            bool fa=0,fb=0;
            if (a<0) a=-a,fa=1;
            if (b<0) b=-b,fb=1;
            exgcd(a,b,c,x,y,d);
            if (a*x+b*y!=c){puts("0");continue;}
            if (fa) a=-a,x=-x;
            if (fb) b=-b,y=-y;
            if (a==0)
            {
                if (y<=0) puts("0");
                else puts("ZenMeZheMeDuo");
                continue;
            }
            if (b==0)
            {
                if (x<=0) puts("0");
                else puts("ZenMeZheMeDuo");
                continue;
            }
            if (a*b<0){puts("ZenMeZheMeDuo");continue;}
            if(a<0) a=-a,b=-b,c=-c;
            a/=d;b/=d;c/=d;x%=b;
            if(x<=0) x+=b;
            y=(c-a*x)/b;
            int miny=y%a;
            if(miny<=0) miny+=a;
            int res=(miny>y)?0:(y-miny)/a+1;
            if(res>65535) puts("ZenMeZheMeDuo");
            else printf("%lld
    ",res);
        }
        return 0;
    }

    T2 染色

    原题目:P3177。

    设$f_{i,j}$表示$i$为根的子树内有$j$个黑点对答案的贡献。然后大力转移就好。可以参考题解。

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define gc getchar
    #define maxn 2005
    using namespace std;
    inline ll read(){
        ll a=0;int f=0;char p=gc();
        while(!isdigit(p)){f|=p=='-';p=gc();}
        while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
        return f?-a:a;
    }
    struct ahaha{
        int w,to,next;
    }e[maxn<<1];int tot,head[maxn];
    inline void add(int u,int v,int w){
        e[tot].w=w,e[tot].to=v,e[tot].next=head[u];head[u]=tot++;
    }
    int n,m,sz[maxn];
    ll f[maxn][maxn];
    void dfs(int u,int fa){
        sz[u]=1;f[u][0]=f[u][1]=0;
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].to;if(v==fa)continue;
            dfs(v,u);sz[u]+=sz[v];
            for(int j=min(m,sz[u]);j>=0;--j){  
                if(f[u][j]!=-1)    
                    f[u][j]+=f[v][0]+(ll)sz[v]*(n-m-sz[v])*e[i].w;
                for(int k=min(j,sz[v]);k;--k){
                    if(f[u][j-k]==-1)continue;
                    ll val=(ll)(k*(m-k)+(sz[v]-k)*(n-m-sz[v]+k))*e[i].w;
                    f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]+val);
                }
            }
        }
    }
    int main(){memset(head,-1,sizeof head);
        n=read();m=read();
        if(n-m<m)m=n-m;
        for(int i=1;i<n;++i){
            int u=read(),v=read(),w=read();
            add(u,v,w);add(v,u,w);
        }memset(f,-1,sizeof f);
        dfs(1,-1);
        printf("%lld",f[1][m]);
        return 0;
    }

    T3 光

    原题目:CF274E

    大力模拟。先考虑暴力怎么做:每次按照光线的方向dfs,直到碰到一个障碍点再反射。这样寻找复杂度是$O(n)$的。而我们现在要将其优化成$log n$。具体做法是把所有对角线编号,对于障碍点扔进STL::set里面,查询的时候lower_bound查找。然后就是一些细节了。考试时候好不容易想出来了做法结果写挂了,还不如交暴力QAQ

    代码:

    #include<set>
    #include<map>
    #include<cstdio>
    #include<iostream>
    using namespace std;
    const int N=200005;
    int n,m,k,sx,sy,d;
    char ch[5];
    long long ans;
    set<int> s1[N],s2[N];
    map<pair<int,int>,bool> mp;
    struct node{
        int x,y,d;
    };
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline int get(int x,int y,int d){
        return d==1?x-y+m+1:x+y;
    }
    inline bool same(node a,node b){
        return a.x==b.x&&a.y==b.y&&a.d==b.d;
    }
    inline bool check(int x,int y){
        return mp[make_pair(x,y)];
    }
    inline void add(int x,int y)
    {
        s1[get(x,y,1)].insert(x);
        s2[get(x,y,2)].insert(x);
        mp[make_pair(x,y)]=1;
    }
    //NE(-1,1) NW(-1,-1) SE(1,1) SW(1,-1)
    //1:NW 2:NE 3:SE 4:SW
    //d:from which dinodetion
    inline pair<node,int> dfs(node u)
    {
        node res;
        set<int>::iterator it;
        if(u.d==1)
        {
            it=s1[get(u.x,u.y,1)].lower_bound(u.x);it--;
            res.x=u.x-(abs(*it-u.x)-1);
            res.y=u.y-(abs(*it-u.x)-1);
            if(check(res.x-1,res.y)&&check(res.x,res.y-1))res.d=3;
            else if(check(res.x-1,res.y)){res.y--;res.d=4;}
            else if(check(res.x,res.y-1)){res.x--;res.d=2;}
            else res.d=3;
        }
        if(u.d==2)
        {
            it=s2[get(u.x,u.y,2)].lower_bound(u.x);it--;
            res.x=u.x-(abs(*it-u.x)-1);
            res.y=u.y+(abs(*it-u.x)-1);
            if(check(res.x-1,res.y)&&check(res.x,res.y+1))res.d=4;
            else if(check(res.x-1,res.y)){res.y++;res.d=3;}
            else if(check(res.x,res.y+1)){res.x--;res.d=1;}
            else res.d=4;
        }
        if(u.d==3)
        {    
            it=s1[get(u.x,u.y,1)].lower_bound(u.x);
            res.x=u.x+(abs(*it-u.x)-1);
            res.y=u.y+(abs(*it-u.x)-1);
            if(check(res.x+1,res.y)&&check(res.x,res.y+1))res.d=1;
            else if(check(res.x+1,res.y)){res.y++;res.d=2;}
            else if(check(res.x,res.y+1)){res.x++;res.d=4;}
            else res.d=1;
        }
        if(u.d==4)
        {
            it=s2[get(u.x,u.y,2)].lower_bound(u.x);
            res.x=u.x+(abs(*it-u.x)-1);
            res.y=u.y-(abs(*it-u.x)-1);
            if(check(res.x+1,res.y)&&check(res.x,res.y-1))res.d=2;
            else if(check(res.x+1,res.y)){res.y--;res.d=1;}
            else if(check(res.x,res.y-1)){res.x++;res.d=3;}
            else res.d=2;
        }
        return make_pair(res,abs(*it-u.x));
    }
    bool judge(node u)
    {
        node res=u;
        do
        {
            pair<node,int> cur=dfs(u);
            ans+=(long long)cur.second;
            switch(cur.first.d)
            {
                case 1:if(u.d==3)return 0;break;
                case 2:if(u.d==4)return 0;break;
                case 3:if(u.d==1)return 0;break;
                case 4:if(u.d==2)return 0;break;
            }
            u=cur.first;
        }while(!same(res,u));
        return 1;
    }
    int main()
    {
        n=read();m=read();k=read();
        for (int i=0;i<=m+1;i++) add(0,i),add(n+1,i);
        for (int i=0;i<=n+1;i++) add(i,0),add(i,m+1);
        for(int i=1;i<=k;i++)
        {
            int x=read(),y=read();
            add(x,y);
        }
        int x=read(),y=read(),d;
        char ch[5];scanf("%s",ch+1);
        if(ch[1]=='N'&&ch[2]=='W')d=1;
        if(ch[1]=='N'&&ch[2]=='E')d=2;
        if(ch[1]=='S'&&ch[2]=='E')d=3;
        if(ch[1]=='S'&&ch[2]=='W')d=4;
        node st={x,y,d};
        st=dfs(st).first;
        if(!judge(st))
        {
            ans--;
            switch(st.d)
            {
                case 1:st.d=3;break;
                case 2:st.d=4;break;
                case 3:st.d=1;break;
                case 4:st.d=2;break;
            }
            judge(st);
        }
        printf("%lld",ans);
        return 0;
    }

    T4 无向图

    题目大意:给定无向图G =(V,E),其中V={1,2,.....n },以及函数p:V →V和f:V →V,
    保证 {p(i)|i∈V }= V。对于 G 的任意路径 P 和 v∈V ,记
    C(P,v)=u∈V(P)[f(u)=v] ,其中V(P)为路径 P 经过的点集(包括起点和终点)。
    对于两条路径P1和P2, P1和P2的比较方法如下:取最小的i,满足C(P1,p(i))
    C(P2,p(i)),则定义C(Pj ,p(i)) 较大的那条路径 Pj较大。若所有C(P1,p(i))=
    C(P2,p(i)),则认为 P1 和 P2 一样大。对于给定的无向图G =(V ,E)及函数 p:V → V 和 f : V → V ,求以1为起
    点、 n为终点的所有路径中最小的一条。

    题面很诡异。大概意思就是对于路径上的所有点,把它们$f$值扔进桶里面,然后按照$p$依次比较字典序。找到字典序最小的那个并输出桶内的值。

    暴力的做法是直接跑最短路,暴力比较。这样修改的复杂度是$O(1)$的,比较的复杂度$O(n)$。我们可以尝试平衡复杂度。一个比较套路的方法是利用主席树。更新属于继承过来,比较实际上可以把两条路径的字典序哈希起来比较。这样修改和查询的复杂度都是$log n$的。

    代码:

    #include<queue>
    #include<cstdio>
    #include<iostream>
    #define ull unsigned long long
    using namespace std;
    const int base=131;
    const int N=100005,M=500005;
    int n,m,t,p[N],f[N],rev[N];
    int rt[N],ls[N*21],rs[N*21],cnt[N*21],tot;
    ull b[N],val[N*21];
    int head[N],edge_cnt;
    bool vis[N],tag[N];
    struct e{
        int next,to;
    }edge[M*2];
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void add(int from,int to)
    {
        edge[++edge_cnt]=(e){head[from],to};
        head[from]=edge_cnt;
    }
    inline void update(int &cur,int l,int r,int pos)
    {
        int x=++tot;
        ls[x]=ls[cur],rs[x]=rs[cur];
        cnt[x]=cnt[cur]+1,val[x]=val[cur]+b[pos],cur=x;
        if(l==r) return;
        int mid=(l+r)>>1;
        if(pos<=mid) update(ls[cur],l,mid,pos);
        else update(rs[cur],mid+1,r,pos);
    }
    inline int query(int x,int y,int l,int r)
    {
        ull v=val[y];
        int c=cnt[y];
        if(t&&t>=l&&t<=r) v+=b[t],c++;
        if(val[x]==v) return 0;
        if(!cnt[x]) return -1;
        if(!c) return 1;
        if(l==r)
        {
            if(cnt[x]==c) return 0;
            if(cnt[x]>c) return 1;
            if(cnt[x]<c) return -1;
        }
        int mid=(l+r)>>1;
        int q=query(ls[x],ls[y],l,mid);
        if(q) return q;
        return query(rs[x],rs[y],mid+1,r);
    }
    struct node{
        int id;
    };
    bool operator < (const node &a,const node &b){
        return query(rt[a.id],rt[b.id],1,n)>=0;
    }
    inline void dijkstra()
    {
        priority_queue<node> q;
        update(rt[1],1,n,rev[f[1]]);q.push({1});tag[1]=1;
        while(!q.empty())
        {
            int x=q.top().id;
            q.pop();
            if(vis[x]) continue;
            vis[x]=true;
            for(int i=head[x];i;i=edge[i].next)
            {
                int y=edge[i].to;
                if(!tag[y]) tag[y]=true,rt[y]=rt[x],update(rt[y],1,n,rev[f[y]]),q.push({y});
                else
                {
                    t=rev[f[y]];
                    if(query(rt[y],rt[x],1,n)==1)
                        rt[y]=rt[x],update(rt[y],1,n,rev[f[y]]),q.push({y});
                    t=0;
                }
            }
        }
    }
    inline void dfs(int cur,int l,int r)
    {
        if(!cur) return;
        if(l==r)
        {
            for(int i=1;i<=cnt[cur];++i) printf("%d ",p[l]);
            return;
        }
        int mid=(l+r)>>1;
        dfs(ls[cur],l,mid),dfs(rs[cur],mid+1,r);
    }
    int main()
    {
        n=read(),m=read(),b[0]=1;
        for(int i=1;i<=n;++i) b[i]=b[i-1]*base;
        for(int i=1;i<=n;++i) p[i]=read(),rev[p[i]]=i;
        for(int i=1;i<=n;++i) f[i]=read();
        for(int i=1;i<=m;++i)
        {
            int x=read(),y=read();
            add(x,y),add(y,x);
        }
        dijkstra(),dfs(rt[n],1,n);
        return 0;
    }
  • 相关阅读:
    Python3+Flask安装使用教程
    Linux getopt/getopts解析命令行参数教程
    Python3+unittest使用教程
    Python3+slowloris安装使用教程
    pytest pluggy.manager.PluginValidationError: unknown hook 'pytest_namespace'报错处理办法
    Python3+Django get/post请求实现教程
    Jenkins安装使用教程
    安全基线自动化扫描、生成报告、加固的实现(以Tomcat为例)
    Scratch安装使用教程
    从安装Mac OS X虚拟机到第一个IOS程序
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/13959723.html
Copyright © 2020-2023  润新知