zoukankan      html  css  js  c++  java
  • 【自家测试】2018-3-3

    A 题
    Dave 写一个程序,他希望这个程序运行之后可以输出长度为 n 的数组 a。
    在这个程序中 Dave 一开始会开若干个临时变量,并在一开始的时候对某一个进行赋值,然
    后将其输出。
    接下来,Dave 每次可以选 3 个变量(变量可以是相同的),设变量为 bi,bj,bk,然后进行
    如下操作
    1,bi = bj + bk
    2,输出 bi
    由于 Dave 电脑内存极小,现在他想他至少需要多少个临时变量。
    输入
    第一行一个 n 表示数组长度
    第二行 n 个数,表示需要输出的数组
    输出
    一个数,表示变量的个数, 无解输出-1
    输入样例
    5
    1 2 3 6 8
    输出样例
    2
    样例解释
    b1 := 1;
    b2 := b1+b1;
    b1 := b1+b2;
    b1 := b1+b1;
    b1 := b1+b2.
    数据范围
    对于 40%的数据 0<a[i]<=1000
    对于 100%的数据 0<a[i]<10^9 ,n<=23

    奥妙重重的状压dp。

    奥妙之处在于它是一个大概4e7的暴力,一个从1递增的数据就可以卡成3s多,加了一个玄学剪枝可以1s过,结果wa完了。。然后不加剪枝竟然过了??

    奥妙重重

    //Achen
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<vector>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    const int N=24;
    typedef long long LL;
    using namespace std;
    int n,a[N],isok[N],ck,dp[2][1<<23],vis[1<<23],lastuse[N],inf,ans;
    
    template<typename T>void read(T &x)  {
        char ch=getchar(); x=0; T f=1;
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') f=-1,ch=getchar();
        for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    }
    
    int ecnt,fir[N],nxt[N*N],to[N*N];
    void add(int u,int v) {
        nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
    }
    
    #define DEBUG
    int main() {
    #ifdef DEBUG
        freopen("A.in","r",stdin);
        freopen("A.out","w",stdout);
    #endif
        read(n);
        for(int i=1;i<=n;i++) read(a[i]);
        for(int i=2;i<=n;i++) {
            for(int j=1;j<i;j++) 
                for(int k=j;k<i;k++) 
                    if(a[j]+a[k]==a[i]) {
                        add(i,((1<<j-1)|(1<<k-1)));
                        isok[i]=1;
                    }
            ck+=isok[i];
        }
        if(ck<n-1) { puts("-1"); return 0; }
        int o=0;
        memset(dp,127,sizeof(dp));
        inf=dp[0][0]; ans=inf;
        dp[o][1]=1;
        for(int i=2;i<=n;i++) {
            o^=1;
            for(int jj=0,j;jj<(1<<i-2);jj++) {
                j=(jj|(1<<i-2));
                if(dp[o^1][j]!=inf) {
                    for(int k=fir[i];k;k=nxt[k]) if((j&to[k])==to[k]) {
                        vis[j|(1<<i-1)]=i;
                        dp[o][j|(1<<i-1)]=min(dp[o][j|(1<<i-1)],dp[o^1][j]+1);
                        for(int l=j;l;l-=(l&(-l))) {
                            int lb=(l&(-l));
                            vis[(j^lb)|(1<<i-1)]=i;
                            dp[o][(j^lb)|(1<<i-1)]=min(dp[o][(j^lb)|(1<<i-1)],dp[o^1][j]);
                        }
                    }
                }
            }
            for(int j=1;j<(1<<i);j++) {
                if(vis[j]!=i) dp[o][j]=inf;
                else if(i==n) ans=min(ans,dp[o][j]);
                /*if(vis[j]==i) {
                    int cnt=0;
                    for(int l=j;l;l-=(l&(-l))) cnt++;
                    if(cnt>(n-i)*2+1) dp[o][j]=inf;
                }*/
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
    /*
    5
    1 2 3 6 8
    
    23
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
    
    23
    1 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
    */
    View Code

    B 题

    有一棵 n 个节点的树,树上的节点从 1 到 n 标号。我们定义一个区间[l,r]的长度为 r-l+1。 对于该树的一棵子树(一个连通子图),我们定义其价值为一个最长的区间[l,r]的长度,并且 所有标号为 l,l+1,...,r 的节点均属于这棵子树。

    现在你需要考虑所有大小不超过 k 的子树,找出一个价值最大的。

    注意在这个问题里面给出 的树是没有根的。

    输入:

    第一行包含两个整数 n,k。

    接下来的 n-1 行每行包含两个整数 ai,bi,表示在 ai 与 bi 间有一条边。

    我们保证这个图构成一棵树。

    输出:

    输出一个整数占一行,表示最大的价值。

    样例输入:

    10 6

    4 10 10

    6 2 9

    9 6 8

    5 7 1

    4 7 7

    3 1 8

    样例输出:

    3

    数据范围:

    对于 10%的数据,1 <= k <= n <= 20;

    对于 30%的数据,1 <= k <= n <= 1000;

    另外有 10%的数据,这棵树是一条链。

    对于 100%的数据,1 <= k <= n <= 100000。

    用两个指针l,r维护l~r形成一个联通块的情况,,开一个set按dfs序维护l~r之间的点,那么目前的lca就是dfs序最小的点和最大点的lca。

    r从1到n扫,加点,当联通块的sz>k时l++,删点。

    加点时加入新点算一遍现在的lca,和从前的lca比较,若有变换,sz加上上一个lca到这个lca之间的点即可。

    若无变化,用树状数组维护子树信息,查询一下当前点的儿子中有没有仍然没被删掉的点,若有则sz不变,否则从set中找到和当前点相邻的点求lca,取深度大的,sz减掉当前点到这个lca之间的点即可。

    删点和加点的方式类似。

    //Achen
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<vector>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    #include<set>
    const int N=100007;
    typedef long long LL;
    using namespace std;
    int n,k,ans=1,szz,lca;
    
    template<typename T>void read(T &x)  {
        char ch=getchar(); x=0; T f=1;
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') f=-1,ch=getchar();
        for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    }
    
    int ecnt,fir[N],nxt[N<<1],to[N<<1],f[N][17],R[N];
    void add(int u,int v) {
        nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
        nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u;
    }
    
    int sum[N];
    void ADD(int x,int v) { for(int i=x;i<=n;i+=(i&(-i)))     sum[i]+=v; }
    int qry(int x) { int rs=0; for(int i=x;i;i-=(i&(-i))) rs+=sum[i]; return rs; }
    
    int get_lca(int x,int y) {
        if(R[x]<R[y]) swap(x,y);
        for(int i=16;i>=0;i--) 
            if(R[f[x][i]]>=R[y])
                x=f[x][i];
        if(x==y) return x;
        for(int i=16;i>=0;i--) 
            if(f[x][i]!=f[y][i]) 
                x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    
    int dfs_clock,dfn[N],sz[N];
    void dfs(int x,int fa) {
        dfn[x]=++dfs_clock;    
        f[dfn[x]][0]=dfn[fa];
        R[dfn[x]]=R[dfn[fa]]+1; 
        sz[dfn[x]]=1;
        for(int i=1;i<=16;i++) f[dfn[x]][i]=f[f[dfn[x]][i-1]][i-1];
        for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) { 
            dfs(to[i],x);
            sz[dfn[x]]+=sz[dfn[to[i]]];
        }
    } 
    
    int inque(int x) { return qry(x+sz[x]-1)-qry(x); }
    
    set<int>s;
    void ins(int x) {
        s.insert(x);
        if(s.size()==1) { ADD(x,1); lca=x; szz=1; return; }
        int nlca=get_lca(*s.begin(),*s.rbegin());
        if(nlca==lca) {
            ADD(x,1);
            if(!inque(x)) {
                int y=(s.lower_bound(x)==s.begin())?0:(*--s.lower_bound(x));
                int z=(++s.lower_bound(x)==s.end())?0:(*++s.lower_bound(x));
                if(!(y*z)) y=z=(y^z);
                y=get_lca(x,y);
                z=get_lca(x,z); 
                if(R[z]>R[y]) swap(z,y); 
                szz+=R[x]-R[y];
            }
        }
        else {
            ADD(x,1);
            szz+=R[x]-R[nlca]+R[lca]-R[nlca];
        }
        lca=nlca;
    }
    
    void del(int x) {
        if(s.size()==1) { s.erase(x);  ADD(x,-1); szz=0; return;}
        s.erase(x);
        int nlca=get_lca(*s.begin(),*s.rbegin());
        s.insert(x);
        if(nlca==lca) {
            if(inque(x)<=1) {
                int y=(s.lower_bound(x)==s.begin())?0:(*--s.lower_bound(x));
                int z=(++s.lower_bound(x)==s.end())?0:(*++s.lower_bound(x));
                if(!(y*z)) y=z=(y^z);
                y=get_lca(x,y);
                z=get_lca(x,z); 
                if(R[z]>R[y]) swap(z,y); 
                szz-=R[x]-R[y];
            }
            ADD(x,-1);
        }
        else {
            ADD(x,-1);
            szz-=R[x]-R[lca]+R[nlca]-R[lca];
        }
        s.erase(x);
        lca=nlca;
    }
    
    void solve() {
        int l=1;
        szz=0; lca=0;
        for(int r=1;r<=n;r++) {
            ins(dfn[r]);
            while(szz>k) 
                del(dfn[l++]);
            ans=max(ans,r-l+1);
        }
    }
    
    #define DEBUG
    int main() {
    #ifdef DEBUG
        freopen("B.in","r",stdin);
        freopen("B.out","w",stdout);
    #endif
        read(n); read(k);
        for(int i=1;i<n;i++) {
            int u,v;
            read(u); read(v);
            add(u,v);
        }
        dfs(1,0);
        solve();
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    C 题
    森林里共有 n 个结点,结点从 1 到 n 编号。森林里共有 m 条有向边,一些结点之间通过有
    向边连接。通过有向边可以从一个结点走到另一个结点,但是通过一条边需要花费其所对应
    的时间。
    有一天,一名农夫闯入了森林。他观察发现,每天都会有一只兔子从 1 号结点跑到 n
    号结点。兔子都很聪明,它总会选择一条从 1 到 n 花费总时间最少的路径,但是兔子每天可
    能会选择不同的路径。农夫仔细研究之后发现无论兔子选择哪条最短路径,都必须经过一些
    特定的结点。也就是说,任何一条从 1 到 n 的最短路都要经过这些结点。于是他只要选择一
    个这样的结点,在那里“守株待兔”便可以抓到兔子了。现在他想知道这样的结点一共有多
    少个。
    输入描述
    第一行两个数 n,m 表示木桩数和边数。
    接下来有 m 行,每行 3 个数 u v w,表示从 u 号木桩到 v 号木桩有一条耗时为 w 的有向边。
    输入保证没有自环和重边。
    输出描述
    如果不能从 1 号木桩到 n 号木桩输出-1,否则输出特定木桩个数。
    输入样例
    5 5
    1 2 2
    1 3 5
    2 4 1
    3 4 4
    4 5 10
    输出样例
    4
    数据范围
    20%的数据 n<=1000,m<=2000
    100%的数据 n<=100000,m<=100000
    1=<u,v<=n,1=<w<=1000

    一种方法是求出起点到每个点的最短路和最短路条数,终点同样,算出经过最短路上的每个点的最短路条数,若是等于总数则计算答案。

    因为最短路会很多,需要hash。

    另一种方法是求出最短路后建出新图求支配点。

    一个过了80的求割点算法。暂时不知道为何会WA。

    //Achen
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<vector>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    const int N=100007;
    typedef long long LL;
    using namespace std;
    int n,m;
    
    template<typename T>void read(T &x)  {
        char ch=getchar(); x=0; T f=1;
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') f=-1,ch=getchar();
        for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    }
    
    int ecnt,fir[N],nxt[N],to[N],val[N];
    int ec,fi[N],nx[N],tt[N],va[N];
    void add(int u,int v,int w) {
        nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w;
        nx[++ec]=fi[v]; fi[v]=ec; tt[ec]=u; va[ec]=w;    
    }
    
    deque<int>que;
    int dis[N],dis2[N],vis[N],is[N];
    void spfa(int fir[],int nxt[],int to[],int val[],int dis[]) {
        while(!que.empty()) {
            int x=que.front();
            que.pop_front(); 
            vis[x]=0;
            for(int i=fir[x];i;i=nxt[i]) {
                if(dis[to[i]]>dis[x]+val[i]) {
                    dis[to[i]]=dis[x]+val[i];
                    if(!vis[to[i]]) {
                        vis[to[i]]=1;
                        if(!que.empty()) {
                            if(dis[to[i]]<dis[que.front()]) que.push_front(to[i]); 
                            else que.push_back(to[i]);
                        }
                        else que.push_back(to[i]); 
                    }
                }
            }
        }
    }
    
    int cnt,Fir[N],Nxt[N<<1],To[N<<1]; 
    void ADD(int u,int v) {
        Nxt[++cnt]=Fir[u]; Fir[u]=cnt; To[cnt]=v;
        Nxt[++cnt]=Fir[v]; Fir[v]=cnt; To[cnt]=u;
    }
    
    int dfs_clock,dfn[N],low[N],cut[N],top,rt,rc;
    void tarjan(int x,int rt) {
        low[x]=dfn[x]=++dfs_clock;
        for(int i=Fir[x];i;i=Nxt[i]) {
            if(!dfn[To[i]]) {
                if(x==rt) rc++;
                tarjan(To[i],rt);
                low[x]=min(low[x],low[To[i]]);
                if(x!=rt&&low[To[i]]>=dfn[x]) cut[x]=1;
            }
            else low[x]=min(low[x],dfn[To[i]]);
        }
        if(x==rt&&rc>1) cut[x]=1;
    }
    
    #define DEBUG
    int main() {
    #ifdef DEBUG
        freopen("C.in","r",stdin);
        freopen("C.out","w",stdout);
    #endif
        read(n); read(m);
        for(int i=1;i<=m;i++) {
            int u,v,w;
            read(u); read(v); read(w);
            add(u,v,w);
        }
        memset(dis,127,sizeof(dis));
        memset(dis2,127,sizeof(dis2));
        dis[1]=0; que.push_back(1);
        spfa(fir,nxt,to,val,dis);
        dis2[n]=0; que.push_back(n); 
        spfa(fi,nx,tt,va,dis2);
        for(int i=1;i<=n;i++) 
            if(dis[i]+dis2[i]==dis[n]) is[i]=1; 
        for(int i=1;i<=n;i++) if(is[i]) {
            for(int j=fir[i];j;j=nxt[j]) if(is[to[j]]) {
                ADD(i,to[j]);
            }
        }
        for(int i=1;i<=n;i++) if(is[i]) {
            tarjan(i,i); break;
        } cut[1]=cut[n]=1;
        int ans=0;
        for(int i=1;i<=n;i++) ans+=cut[i];
        printf("%d
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    动态传参
    函数的介绍
    文件的操作
    send email with formatted table
    minimize and close window with customed winform
    python algorithm
    something important about docker
    book list
    which language is suitable for what to do
    Find Duplicate Items in list fast
  • 原文地址:https://www.cnblogs.com/Achenchen/p/8502830.html
Copyright © 2011-2022 走看看