zoukankan      html  css  js  c++  java
  • 清北刷题冲刺 10-30 p.m

    少女

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstdlib>
    #define maxn 200010
    #define mod 1000000007
    using namespace std;
    int n,m,head[maxn],num,c[maxn],du[maxn];
    int ans=1;
    bool vis[maxn];
    struct node{
        int to,pre,v;
    }e[maxn*2];
    void Insert(int from,int to,int id,int v){
        e[id].to=to;
        e[id].v=v;
        e[id].pre=head[from];
        head[from]=id;
    }
    int Pow(int a,int b){
        int res=1;
        while(b){
            if(b&1)res=1LL*res*a%mod;
            a=1LL*a*a%mod;
            b>>=1;
        }
        return res;
    }
    void bfs(int s){
        int count=0;
        queue<int>q;
        q.push(s);vis[s]=1;
        int cnt=0;//记录联通块中有多少边 
        while(!q.empty()){
            int now=q.front();q.pop();
            count+=c[now];
            while(count>=mod)count-=mod;
            for(int i=head[now];i;i=e[i].pre){
                if(e[i].v){
                    e[i].v=0;
                    int nxt;
                    if(i>m)nxt=i-m;
                    if(i<=m)nxt=i+m;
                    e[nxt].v=0;
                    cnt+=1;
                    if(!vis[e[i].to]){
                        vis[e[i].to]=1;
                        q.push(e[i].to);
                    }
                }
            }
        }
        int w=Pow(2,cnt)-count;
        if(w<=0){
            puts("0");exit(0);
        }
        ans=1LL*ans*w%mod;
        while(ans>=mod)ans-=mod;
    }
    int main(){
        freopen("girl.in","r",stdin);freopen("girl.out","w",stdout);
    //    freopen("Cola.txt","r",stdin);
        scanf("%d%d",&n,&m);
        int x,y;
        for(int i=1;i<=m;i++){
            scanf("%d%d",&x,&y);
            if(x==y)y+=n,n++;
            Insert(x,y,i,1);Insert(y,x,i+m,1);
            du[x]++;du[y]++;
        }
        for(int i=1;i<=n;i++){
            c[i]=Pow(2,du[i])-1-du[i];
            while(c[i]<0)c[i]+=mod;
        }
        for(int i=1;i<=n;i++){
            if(!vis[i]){
                bfs(i);
            }
        }
        printf("%d",ans);
        return 0;
    }
    0分
    /*
        对于图上每个联通块:
        有>=2个环就无解;
        有一个环就有2个解(顺时针和逆时针);
        没有环,就是一棵树,n个点,n-1条边,所以有一个点没有边匹配,这个点有n种情况,所以有n个解 
    */
    #include<iostream>
    #include<cstdio>
    #define maxn 100010
    #define mod 1000000007
    using namespace std;
    int n,m,x,y,fa[maxn],r[maxn],sz[maxn];
    bool vis[maxn];
    int find(int x){
        if(x==fa[x])return x;
        else return fa[x]=find(fa[x]);
    }
    int main(){
        freopen("girl.in","r",stdin);freopen("girl.out","w",stdout);
    //    freopen("Cola.txt","r",stdin);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)fa[i]=i,sz[i]=1;
        for(int i=1;i<=m;i++){
            scanf("%d%d",&x,&y);
            int f1=find(x),f2=find(y);
            if(f1==f2){
                if(r[f1]){
                    puts("0");
                    return 0;
                }
                else r[f1]=1;
            }
            else {
                fa[f2]=f1;
                r[f1]|=r[f2];
                sz[f1]+=sz[f2];
                sz[f2]=0;
            }
        }
        long long ans=1;
        for(int i=1;i<=n;i++){
            int father=find(i);
            if(!vis[father]){
                vis[father]=1;
                if(r[father])ans=2LL*ans%mod;
                else ans=1LL*sz[father]*ans%mod;
            }
        }
        cout<<ans;
        return 0;
    }
    100分 并查集判环

    终末

    #include<iostream>
    #include<cstdio>
    using namespace std;
    long long n,bin[1000],ans,a[1000];
    int k,cnt=-1;
    long long Pow(long long a,long long b){
        long long res=1;
        while(b){
            if(b&1)res=1LL*res*a;
            a=1LL*a*a;
            b>>=1;
        }
        return res;
    }
    int main(){
    //    freopen("Cola.txt","r",stdin);
    //    freopen("endless.in","r",stdin);freopen("endless.out","w",stdout);
        cin>>n>>k;
        int t=0;
        while(1){
            cnt=cnt+1;
            bin[cnt]=Pow(k,cnt);
            if(bin[cnt]>n)break;
        }
        for(long long i=0;i<=n;i++){
            bool flag=0;
            long long now=i;
            for(int j=cnt;j>=0;j--){
                a[j]=now/bin[j];
                if(a[j]&&(j&1)){
                    flag=1;break;
                }
                now-=a[j]*bin[j];
            }
            if(flag==0)ans++;
        }
        cout<<ans;
    }
    40分 暴力
    /*
        满足条件的数必须有一个性质,转成k进制后偶数位为0,奇数位为0~k-1
        所以就是求<=n的数转化为k进制后偶数位全部为0的方案数
        可以用数位dp求解 
    */
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    LL bit[67];
    int a[67];
    int main(){    
        freopen("endless.in","r",stdin);freopen("endless.out","w",stdout);
        long long n;int k;LL ans=0;
        scanf("%I64d%d",&n,&k);
        int len=0;
        while(n) a[++len]=n%k,n/=k;
        if(!(len&1)){
            ans=pow(1LL*k,len/2);
            cout<<ans;
        }
        else{
            for(int i=len;i>=1;i--)
                if(a[i]){
                    if(!(i&1)){ans+=pow(1LL*k,i/2);break;}
                    ans+=1LL*a[i]*pow(1LL*k,i/2);
                    if(i==1)ans++;
                }
            cout<<ans;
        }
    }
    100分 数位dp

    旅行

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define maxn 100010
    using namespace std;
    int n,num,head[maxn],v[maxn],k,le[maxn],cnt;
    long long w[maxn],ans,sum;
    int top[maxn],fa[maxn],son[maxn],sz[maxn],dep[maxn];
    struct node{
        int to,pre;
    }e[maxn*2];
    void Insert(int from,int to){
        e[++num].to=to;
        e[num].pre=head[from];
        head[from]=num;
    }
    void dfs1(int now,int father){
        dep[now]=dep[father]+1;
        fa[now]=father;
        sz[now]=1;
        w[now]=w[father]+v[now];
        bool flag=0;
        for(int i=head[now];i;i=e[i].pre){
            int to=e[i].to;
            if(to==father)continue;
            dfs1(to,now);
            sz[now]+=sz[to];
            if(!son[now]||sz[to]>sz[son[now]])son[now]=to;
            flag=1;
        }
        if(!flag)le[++cnt]=now;
    }
    void dfs2(int now,int father){
        top[now]=father;
        if(son[now])dfs2(son[now],father);
        for(int i=head[now];i;i=e[i].pre){
            int to=e[i].to;
            if(to==fa[now]||to==son[now])continue;
            dfs2(to,to);
        }
    }
    int lca(int a,int b){
        while(top[a]!=top[b]){
            if(dep[top[a]]<dep[top[b]])swap(a,b);
            a=fa[top[a]];
        }
        if(dep[a]>dep[b])swap(a,b);
        return a;
    }
    int q[maxn];
    void count(){
        long long now=0;
        for(int i=1;i<=k;i++)now+=w[q[i]];
        for(int i=1;i<=k;i++)
            for(int j=i+1;j<=k;j++)
                now-=w[lca(q[i],q[j])];
        ans=max(ans,now);
    }
    void dfs(int pos,int c){
        if(c==k+1){
            count();
            return;
        }
        if(pos>cnt)return;
        if(cnt-pos<k-c)return;
        q[c]=le[pos];
        dfs(pos+1,c+1);
        dfs(pos+1,c);
    }
    bool flag=1;
    bool cmp(int x,int y){return x>y;}
    int main(){
        freopen("tour.in","r",stdin);freopen("tour.out","w",stdout);
    //    freopen("Cola.txt","r",stdin);
        scanf("%d%d",&n,&k);
        if(k==0){
            puts("0");
            return 0;
        }
        int x,y;
        for(int i=1;i<=n;i++)scanf("%d",&v[i]),sum+=v[i];
        for(int i=1;i<n;i++){
            scanf("%d%d",&x,&y);
            Insert(x,y);Insert(y,x);
            if(x!=1&&y!=1)flag=0;
        }
        if(flag){
            ans=v[1];
            v[1]=0;
            sort(v+1,v+n+1,cmp);
            for(int i=1;i<=k;i++){
                ans+=v[i];
            }
            cout<<ans;
            return 0;
        }
        dfs1(1,0);
        dfs2(1,1);
        if(k>=cnt){
            cout<<sum;
            return 0;
        }
        dfs(1,1);
        cout<<ans;
        return 0;
    }
    30分 暴力
    /*
        对树上的所有叶子节点到根的前缀和建一棵线段树,每次贪心选择前缀和最大的节点,并把路径上所有点为根节点的子树的叶子节点的前缀和减那个数,每次修改的都是一个连续的区间,所以可以用线段树的区间修改进行维护
    */
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    #define maxn 100010
    int n,m,val[maxn],head[maxn],num;
    int opl,opr;long long opv;
    struct node{
        int to,pre;
    }e[maxn*2];
    int F[maxn],fa[maxn],id[maxn],cnt,L[maxn],R[maxn];
    long long w[maxn],mx[maxn<<2],pos[maxn<<2],tag[maxn<<2];
    void Insert(int from,int to){
        e[++num].to=to;
        e[num].pre=head[from];
        head[from]=num;
    }
    void init(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&val[i]);
        int x,y;
        for(int i=1;i<n;i++){
            scanf("%d%d",&x,&y);
            Insert(x,y);Insert(y,x);
        }
    }
    void dfs(int now,int father,long long sum){
        L[now]=cnt+1;
        F[now]=now;bool leaf=1;
        fa[now]=father;
        for(int i=head[now];i;i=e[i].pre){
            int to=e[i].to;
            if(to==father)continue;
            leaf=0;
            dfs(to,now,sum+val[to]);
        }
        if(leaf)w[++cnt]=sum,id[cnt]=now;
        R[now]=cnt;
    }
    void build(int l,int r,int k){
        if(l==r){mx[k]=w[l];pos[k]=l;return;}
        int mid=(l+r)>>1;
        build(l,mid,k<<1);
        build(mid+1,r,k<<1|1);
        mx[k]=max(mx[k<<1],mx[k<<1|1]);
        pos[k]=(mx[k]==mx[k<<1]?pos[k<<1]:pos[k<<1|1]);
    }
    void down(int k){
        mx[k<<1]-=tag[k];
        mx[k<<1|1]-=tag[k];
        tag[k<<1]+=tag[k];
        tag[k<<1|1]+=tag[k];
        tag[k]=0;
    }
    void change(int k,int l,int r){
        if(opl<=l&&opr>=r){
            mx[k]-=opv;
            tag[k]+=opv;
            return;
        }
        if(tag[k])down(k);
        int mid=(l+r)>>1;
        if(opl<=mid)change(k<<1,l,mid);
        if(opr>mid)change(k<<1|1,mid+1,r);
        mx[k]=max(mx[k<<1],mx[k<<1|1]);
        pos[k]=(mx[k]==mx[k<<1]?pos[k<<1]:pos[k<<1|1]);
    }
    int find(int x){
        if(x==F[x])return x;
        return F[x]=find(F[x]);
    }
    void solve(){
        int p;long long ans=0;
        while(m--){
            p=id[pos[1]];
            ans+=mx[1];
            while(p){
                opl=L[p];opr=R[p];opv=val[p];
                change(1,1,cnt);
                F[p]=find(F[fa[p]]);
                p=F[p];
            }
        }
        cout<<ans;
    }
    int main(){
        freopen("tour.in","r",stdin);freopen("tour.out","w",stdout);
    //    freopen("Cola.txt","r",stdin);
        init();
        dfs(1,0,val[1]);
        build(1,cnt,1);
        solve();
    }
    100分 线段树
    预计得分100+40+30
    实际得分0+40+30
    T1错误比较大,是思路有误,根本原因在于自己造的样例没有包括全部的情况,以后引以为戒,不光要多造样例,更要尽可能想到更多的情况。T2T3写的时间不多,T2暴力分拿到了,T3wa了好几个,不知道为什么
    今天下午时间把握不好,T1上浪费的时间太多而且思路偏离,T2T3草草写了暴力,难免出错,下不为例
    小结
  • 相关阅读:
    利用async和await异步操作解决node.js里面fs模块异步读写,同步结果的问题
    node.js的fs核心模块读写文件操作 -----由浅入深
    node.js 发布订阅模式
    js 发布订阅模式
    vue.js定义一个一级的路由 ----由浅入深
    vue.js编程式路由导航 --- 由浅入深
    vue.js嵌套路由-------由浅入深
    Spring事件体系
    Hibernate监听器
    学习网站地址
  • 原文地址:https://www.cnblogs.com/thmyl/p/7754961.html
Copyright © 2011-2022 走看看