1588. [USACO FEB04]距离咨询


★★   输入文件:dquery.in   输出文件:dquery.out   简单对比
时间限制:1 s   内存限制:256 MB



【题目描述】



农夫约翰有N(2<=N<=40000)个农场,标号1到N。M(2<=M<=40000)条的不同的垂直或水平的道路连结着农场,道路的长度不超过1000.这些农场的分布就像下面的地图一样,图中农场用F1..F7表示:

 

每个农场最多能在东西南北四个方向连结4个不同的农场。此外,农场只处在道路的两端。道路不会交叉而且每对农场间有且仅有一条路径。邻居鲍伯要约翰来导航,但约翰丢了农场的地图,他只得从电脑的备份中修复率。每一条道路的信息如下:

    从农场23往南经距离10到达农场17

    从农场1往东经距离7到达农场17

    . . .

最近美国过度肥胖非常普遍。农夫约翰为了让他的奶牛多做运动,举办了奶牛马拉松。马拉松路线要尽量长。

奶牛们拒绝跑马拉松,因为她们悠闲的生活无法承受约翰选择的如此长的赛道。因此约翰决心找一条更合理的赛道。他打算咨询你。读入地图之后会有K个问题,每个问题包括2个整数,就是约翰感兴趣的2个农场的编号,请尽快算出这2个农场间的距离。



【输入格式】



第1行:两个分开的整数N和M。

第2到M+1行:每行包括4个分开的内容,F1,F2,L,D分别描述两个农场的编号,道路的长度,F1到F2的方向N,E,S,W。

第2+M行:一个整数K(1<=K<=10000).

第3+M到2+M+K行:每行输入2个整数,代表2个农场。



【输出格式】



对每个问题,输出单独的一个整数,给出正确的距离。



【样例输入】



7 6
 
  
1 6 13 E
 
  
6 3 9 E
 
  
3 5 7 S
 
  
4 1 3 N
 
  
2 4 20 W
 
  
4 7 2 S
 
  
3
 
  
1 6
 
  
1 4
 
  
2 6



【样例输出】



13
 
  
3
 
  
36



AC代码:



#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<map>
using namespace std;
#define N 100010
#define ll long long
#define xx first
#define yy second
typedef pair<int,int> diy;
inline const int read(){
    register int x=0,f=1;
    register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline const char in(){
    for(register char ch=getchar();;ch=getchar()) if((ch>='A'&&ch<='Z')) return ch;
}
struct node{
    int u,v,w;
    bool operator < (const node &a) const {
        return w>a.w;
    }
}ed[N];
struct ss{
    int v,w,next;
}e[N<<1];
int tot,head[N],dep[N],f[N][21],dis[N],fa[N];
void add(int x,int y,int z){
    e[++tot].v=y;
    e[tot].w=z;
    e[tot].next=head[x];
    head[x]=tot;
}
int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
void dfs(int x,int from,int de,int len){
    dep[x]=de;
    f[x][0]=from;
    dis[x]=len;
    for(int i=head[x];i;i=e[i].next){
        if(e[i].v!=from){
            dfs(e[i].v,x,de+1,len+e[i].w);
        }
    }
}
int lca(int a,int b){
    if(dep[a]<dep[b]) swap(a,b);
    int t=dep[a]-dep[b];
    for(int i=0;i<=20;i++){
        if((1<<i)&t){
            a=f[a][i];
        }
    }
    if(a==b) return a;
    for(int i=20;i>=0;i--){
        if(f[a][i]!=f[b][i]){
            a=f[a][i];
            b=f[b][i];
        }
    }
    return f[a][0];
}
int main(){
    freopen("dquery.in","r",stdin);
    freopen("dquery.out","w",stdout);
    int n=read(),m=read();char c;
    for(int i=1,x,y,z;i<=m;i++){
        ed[i].u=read();
        ed[i].v=read();
        ed[i].w=read();
        c=in(); 
    }
    sort(ed+1,ed+m+1);
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1,fx,fy;i<=m;i++){
        fx=find(ed[i].u),fy=find(ed[i].v);
        if(fx!=fy){
            fa[fy]=fx;
            add(ed[i].u,ed[i].v,ed[i].w);
            add(ed[i].v,ed[i].u,ed[i].w);
        }
    }
    //dep[1]=1;
    dfs(1,0,1,0);
    for(int j=1;j<=20;j++){
        for(int i=1;i<=n;i++){
            f[i][j]=f[f[i][j-1]][j-1];
        }
    }
    int K=read();
    while(K--){
        int x=read(),y=read();
        int anc=lca(x,y);
        int ans=dis[x]+dis[y]-(dis[anc]<<1);
        printf("%d\n",ans);
    }
    return 0;
}



 

1267. [NOIP2012] 疫情控制



★★★☆   输入文件:blockade.in   输出文件:blockade.out   简单对比
时间限制:2 s   内存限制:128 MB



【题目描述】



H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树, 1 号城市是首都, 也是树中的根节点。 

H 国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境 城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境 城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是, 首都是不能建立检查点的。 

现在,在 H 国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在 一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等 于道路的长度(单位:小时)。 

请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。



【输入格式】



第一行一个整数 n,表示城市个数。 

接下来的 n-1 行,每行 3 个整数,u、v、w,每两个整数之间用一个空格隔开,表示从 城市 u 到城市 v 有一条长为 w 的道路。数据保证输入的是一棵树,且根节点编号为 1。 

接下来一行一个整数 m,表示军队个数。 

接下来一行 m 个整数,每两个整数之间用一个空格隔开,分别表示这 m 个军队所驻扎 的城市的编号。



【输出格式】



共一行,包含一个整数,表示控制疫情所需要的最少时间。如果无法控制疫情则输出-1。



【样例输入】



4
 
  
1 2 1
 
  
1 3 2
 
  
3 4 3
 
  
2
 
  
2 2



【样例输出】



3



【输入输出样例说明】



第一支军队在 2 号点设立检查点,第二支军队从 2 号点移动到 3 号点设立检查点,所需 时间为 3 个小时。



【数据范围】



保证军队不会驻扎在首都。 

对于 20%的数据,2≤ n≤ 10; 

对于 40%的数据,2 ≤n≤50,0<w <10^5; 

对于 60%的数据,2 ≤ n≤1000,0<w <10^6; 

对于 80%的数据,2 ≤ n≤10,000; 

对于 100%的数据,2≤m≤n≤50,000,0<w <10^9

AC代码:



#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<map>
using namespace std;
#define N 100010
#define ll long long
#define xx first
#define yy second
typedef pair<int,int> diy;
inline const int read(){
    register int x=0,f=1;
    register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline const char in(){
    for(register char ch=getchar();;ch=getchar()) if((ch>='A'&&ch<='Z')) return ch;
}
struct ss{
    int v,w,next;
}e[N<<1];
struct node{
    int u,v;
}b[N],c[N];
int tot,head[N];
int dep[N],f[N][21],g[N][21],a[N];
bool vis[N];
int n,m,l,r,mid;
void add(int x,int y,int z){
    e[++tot].v=y;
    e[tot].w=z;
    e[tot].next=head[x];
    head[x]=tot;
}
bool cmp(const node &a,const node &b){
    return a.v<b.v;
}
void dfs(int x,int y){
    for(int i=head[x];i;i=e[i].next){
        if(e[i].v!=y){
            f[e[i].v][0]=x;
            g[e[i].v][0]=e[i].w;
            dep[e[i].v]=dep[x]+1;
            dfs(e[i].v,x);
        }
    }
}
int lca(int a,int b){
    if(dep[a]<dep[b]) swap(a,b);
    int t=dep[a]-dep[b];
    for(int i=0;i<=20;i++){
        if((1<<i)&t){
            a=f[a][i];
        }
    }
    if(a==b) return a;
    for(int i=20;i>=0;i--){
        if(f[a][i]!=f[b][i]){
            a=f[a][i];
            b=f[b][i];
        }
    }
    return f[a][0];
}
void color(int x){//如果不能到达1点,那就停在最高点 
    bool p=1,q=0;
    for(int i=head[x];i;i=e[i].next){
        if(e[i].v!=f[x][0]){
            color(e[i].v);
            p&=vis[e[i].v];
            q=1;
        }
    }
    if(p&&q&&x!=1) vis[x]=1;
}
bool check(int x){
    memset(vis,0,sizeof vis);
    int cnt=0,top=0;
    for(int i=1;i<=m;i++){
        int y=a[i],z=0,k=a[i];
        for(int j=20;j>=0;j--){
            if(f[y][j]&&z+g[y][j]<=x){
                z+=g[y][j];
                y=f[y][j];
            }
        }
        if(y!=1) vis[y]=1;
        else{//如果能到达1点,就跳到1的儿子节点 
            b[++cnt].v=x-z;
            y=a[i];
            for(int j=20;j>=0;j--){
                if(f[y][j]>1){
                    y=f[y][j];
                }
            }
            b[cnt].u=y;
        }
    }
    color(1);
    for(int i=head[1];i;i=e[i].next){
        if(!vis[e[i].v]){
            c[++top].u=e[i].v;
            c[top].v=e[i].w;
        }
    }
    sort(b+1,b+cnt+1,cmp);//升序:剩余路程 
    sort(c+1,c+top+1,cmp);//升序:到根节点的距离(没有覆盖的跟的叶子节点) 
    int j=1;
    c[top+1].v=0x3f3f3f3f;//限制 
    for(int i=1;i<=cnt;i++){
        if(!vis[b[i].u]) vis[b[i].u]=1;
        else if(b[i].v>=c[j].v) vis[c[j].u]=1;
        while(vis[c[j].u]) j++;
    }
    return j>top;
}
int main(){
    freopen("blockade.in","r",stdin);
    freopen("blockade.out","w",stdout);
    n=read();
    for(int i=1,x,y,z;i<n;i++) x=read(),y=read(),z=read(),add(x,y,z),add(y,x,z),r+=z;
    m=read();
    for(int i=1;i<=m;i++) a[i]=read();
    dfs(1,1);
    for(int j=1;j<=20;j++){
        for(int i=1;i<=n;i++){
            f[i][j]=f[f[i][j-1]][j-1];
            g[i][j]=g[f[i][j-1]][j-1]+g[i][j-1];
        }
    }
    while(l<r){
        mid=(l+r>>1);
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    printf("%d\n",check(l)?l:-1);
    return 0;
}



 

 

Code



Time Limit: 1000MS

 

Memory Limit: 65536K

Total Submissions: 2475

 

Accepted: 865



Description

KEY Inc., the leading company in security hardware, has developed a new kind of safe. To unlock it, you don't need a key but you are required to enter the correct n-digit code on a keypad (as if this were something new!). There are several models available, from toy safes for children (with a 2-digit code) to the military version (with a 6-digit code). 

The safe will open as soon as the last digit of the correct code is entered. There is no "enter" key. When you enter more than n digits, only the last n digits are significant. For example (in the 4-digit version), if the correct code is 4567, and you plan to enter the digit sequence 1234567890, the door will open as soon as you press the 7 key. 

The software to create this effect is rather simple. In the n-digit version the safe is always in one of 10n-1 internal states. The current state of the safe simply represents the last n-1 digits that have been entered. One of these states (in the example above, state 456) is marked as the unlocked state. If the safe is in the unlocked state and then the right key (in the example above, 7) is pressed, the door opens. Otherwise the safe shifts to the corresponding new state. For example, if the safe is in state 456 and then you press 8, the safe goes into state 568. 

A trivial strategy to open the safe is to enter all possible codes one after the other. In the worst case, however, this will require n * 10n keystrokes. By choosing a good digit sequence it is possible to open the safe in at most 10n + n - 1 keystrokes. All you have to do is to find a digit sequence that contains all n-digit sequences exactly once. KEY Inc. claims that for the military version (n=6) the fastest computers available today would need billions of years to find such a sequence - but apparently they don't know what some programmers are capable of...

Input

The input contains several test cases. Every test case is specified by an integer n. You may assume that 1<=n<=6. The last test case is followed by a zero.

Output

For each test case specified by n output a line containing a sequence of 10n + n - 1 digits that contains each n-digit sequence exactly once.

Sample Input



1
 
 
2
 
 
0



Sample Output


00102030405060708091121314151617181922324252627282933435363738394454647484955657585966768697787988990


Source

Ulm Local 2004

题意:(题意较复杂)大致思想是给你一个n,表示一个由0-9数字构成的n位密码.这个解锁过程如下:锁一直读入所有内容.只要当它最后读入的n个数字与密码吻合,那么就表示解锁了.现在要你输出一个长度为10^n+n-1的数字序列,这个数字序列包括了n位密码的所有可能.(也就是说输入这个序列,必定解锁)

AC代码:



#include<cstdio>
#include<cstring>
using namespace std;
#define N 1000010
const int pow[7]={1,10,100,1000,10000,100000,1000000};
int n,top,cnt[N],st[N];
bool vis[N];
void dfs(){
    for(int i=1;i<n;i++) putchar('0');
    memset(vis,0,sizeof vis);
    memset(cnt,0,sizeof cnt);
    vis[0]=1;
    st[top=1]=0;
    while(top!=pow[n]){
        int u=st[top];
        if(cnt[u]==10){
            vis[u]=0;
            cnt[u]=0;
            --top;
            continue;
        }
        ++cnt[u];
        int v=(u*10+cnt[u]-1)%pow[n];
        if(vis[v]) continue;
        vis[v]=1;
        st[++top]=v;
    }
    for(int i=1;i<=top;i++) printf("%d",st[i]%10);
}
int main(){
    while(scanf("%d",&n)==1){
        if(!n) break;
        if(n==1) printf("0123456789");
        else dfs();
        putchar('\n');
    }
    return 0;
}