【自家测试】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
原文地址:https://www.cnblogs.com/Achenchen/p/8502830.html