zoukankan      html  css  js  c++  java
  • vjudge个人赛 复习1

    A - 大鱼吃小鱼(栈)

     有N条鱼每条鱼的位置及大小均不同,他们沿着X轴游动,有的向左,有的向右。游动的速度是一样的,两条鱼相遇大鱼会吃掉小鱼。从左到右给出每条鱼的大小和游动的方向(0表示向左,1表示向右)。问足够长的时间之后,能剩下多少条鱼?Input第1行:1个数N,表示鱼的数量(1 <= N <= 100000)。 
    第2 - N + 1行:每行两个数A[i], B[i],中间用空格分隔,分别表示鱼的大小及游动的方向(1 <= A[i] <= 10^9,B[i] = 0 或 1,0表示向左,1表示向右)。Output输出1个数,表示最终剩下的鱼的数量。Sample Input

    5
    4 0
    3 1
    2 0
    1 0
    5 0

    Sample Output

    2
    /*
        对于第i条鱼,如果方向朝右进栈。向左的话,跟栈每一个元素j比较,如果i>j   那么j死,继续访问j前面的元素(知道栈空或者死),,, 否则i死,  继续遍历i+1以及后面的元素
    */
    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define maxn 100010
    int st[maxn],top,n,cnt;
    int main(){
        scanf("%d",&n);cnt=n;
        int x,y;
        for(int i=1;i<=n;i++){
            scanf("%d%d",&x,&y);
            if(y==1)st[++top]=x;
            else{
                while(top){
                    if(x>st[top]){top--;cnt--;}
                    else {cnt--;break;}
                }
            }
        }
        cout<<cnt;
    }
    AC代码 用栈维护

    B - 线段的重叠(贪心)

    X轴上有N条线段,每条线段包括1个起点和终点。线段的重叠是这样来算的,[10 20]和[12 25]的重叠部分为[12 20]。
    给出N条线段的起点和终点,从中选出2条线段,这两条线段的重叠部分是最长的。输出这个最长的距离。如果没有重叠,输出0。
     

    Input第1行:线段的数量N(2 <= N <= 50000)。 
    第2 - N + 1行:每行2个数,线段的起点和终点。(0 <= s , e <= 10^9)Output输出最长重复区间的长度。Sample Input

    5
    1 5
    2 4
    2 8
    3 7
    7 9

    Sample Output

    4
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define maxn 50010
    using namespace std;
    int n;
    struct node{
        int l,r;
        bool operator < (const node a)const{
            return l<a.l;
        }
    }e[maxn];
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&e[i].l,&e[i].r);
        sort(e+1,e+n+1);
        int ans=0;
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++){
                if(e[i].r>e[j].r)
                    ans=max(ans,e[j].r-e[j].l);
                else 
                    ans=max(ans,e[i].r-e[j].l);
            }
        cout<<ans;
    }
    80分 n^2暴力
    /*
        贪心,按照线段左端点升序排序, 
        左端点相等,右端点降序排序 
    */  
    #include<iostream>  
    #include<algorithm>  
    #include<cmath>  
    using namespace std;  
    const int MAX=50005;  
    struct Node{  
        int b,e;  
    };  
    Node a[MAX];  
    int cmp(Node p1,Node p2){  
        if(p1.b<p2.b) return 1;  
        else if(p1.b==p2.b&&p1.e>p2.e) return 1;  
        return 0;  
    }  
    int main()  
    {  
        int n;  
        while(cin>>n){  
            for(int i=0;i<n;i++){  
                cin>>a[i].b>>a[i].e;  
            }  
            sort(a,a+n,cmp);  
            int res=0;  
            Node s=a[0];  
            for(int i=1;i<n;i++){  
                if(a[i].e<=s.e){//线段i在线段i-1内  
                    res=max(res,a[i].e-a[i].b);  
                }  
                else if(a[i].b<=s.e&&a[i].e>s.e){  
                    res=max(res,s.e-a[i].b);  
                    s=a[i];//选择最靠后的线段  
                }  
                else s=a[i];
            }  
            cout<<res<<endl;  
        }  
        return 0;  
    }
    100分 贪心

    C - 3个数和为0(暴力枚举)

     给出一个长度为N的无序数组,数组中的元素为整数,有正有负包括0,并互不相等。从中找出所有和 = 0的3个数的组合。如果没有这样的组合,输出No Solution。如果有多个,按照3个数中最小的数从小到大排序,如果最小的数相等则按照第二小的数排序。

     

    Input第1行,1个数N,N为数组的长度(0 <= N <= 1000) 
    第2 - N + 1行:A[i](-10^9 <= A[i] <= 10^9)Output如果没有符合条件的组合,输出No Solution。 
    如果有多个,按照3个数中最小的数从小到大排序,如果最小的数相等则继续按照第二小的数排序。每行3个数,中间用空格分隔,并且这3个数按照从小到大的顺序排列。Sample Input

    7
    -3
    -2
    -1
    0
    1
    2
    3

    Sample Output

    -3 0 3
    -3 1 2
    -2 -1 3
    -2 0 2
    -1 0 1
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define maxn 1010
    int n,a[maxn],b[4];
    void dfs(int pos,int cnt,int sum){
        if(cnt==4){
            if(sum==0){
                for(int i=1;i<=3;i++)printf("%d ",b[i]);
                printf("
    ");
            }
            return;
        }
        if(pos>n)return;
        for(int i=pos;i<=n;i++){
            b[cnt]=a[i];
            dfs(i+1,cnt+1,sum+a[i]);
        }
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        sort(a+1,a+n+1);
        dfs(1,1,0);//到底几个数了,已经确定了几个数-1,目前的和 
    }
    60分 暴力
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define maxn 1010
    int n,a[maxn];
    bool flag;
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        sort(a+1,a+n+1);
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                for(int k=j+1;k<=n;k++)
                    if(a[i]+a[j]+a[k]==0){
                        flag=1;
                        printf("%d %d %d
    ",a[i],a[j],a[k]);
                    }
        if(!flag)printf("No Solution");
        return 0;
    }
    100分 枚举n^3

    D - 复杂度n^2log(n^2)(折半枚举)

     给出N个整数,你来判断一下是否能够选出4个数,他们的和为0,可以则输出"Yes",否则输出"No"。Input第1行,1个数N,N为数组的长度(4 <= N <= 1000) 
    第2 - N + 1行:A[i](-10^9 <= A[i] <= 10^9)Output如果可以选出4个数,使得他们的和为0,则输出"Yes",否则输出"No"。Sample Input

    5
    -1
    1
    -5
    2
    4

    Sample Output

    Yes
    #include<iostream>
    #include<cstdio>
    #include<map>
    #include<algorithm>
    using namespace std;
    int n,a[1010];
    map<int,bool>f;
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        sort(a+1,a+n+1);
        int mid=n/2;
        for(int i=1;i<=mid;i++){
            for(int j=i+1;j<=mid;j++){
                int x=a[i]+a[j];
                f[x]=1;
            }
        }
        for(int i=mid+1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                int x=-(a[i]+a[j]);
                if(f[x]){
                    printf("Yes");
                    return 0;
                }
            }
        }
        printf("No");
        return 0;
    }
    排序+暴力+二分1
    #include<iostream>
    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    int a[1100];
    int main(){
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        sort(a,a+n);
        for(int i=0;i<n;i++)
            for(int j=i+1;j<n;j++){
                int k,m,sum;
                k=j+1;
                m=n-1;
                while(k<m) {
                    sum=a[i]+a[j]+a[k]+a[m];
                    if(sum<0)k++;
                    else if(sum>0)m--;
                    else{
                        k++;m--;
                        printf("Yes
    ");
                        return 0;
                    }
                }
            }
        printf("No
    ");
        return 0;
    }
    排序+暴力+二分2
    /*
        还有个很好的思路,先把数组中任意两个数存起来,再从小到大排序,类似二分的思想从两头开始查找,是否满足sum1+sum2==0 并且两个坐标不重叠,每个点只选一次
    */
    #include <iostream>
    #include <stdio.h>
    #include <algorithm>
    using namespace std;
    int a[1100];
    struct node{
        int x, y;
        int sum;
    }P[1100*1100];
    
    int cmp(node a, node b) {
        return a.sum < b.sum;
    }
    int main(){
        int n;
        scanf("%d", &n);
        for(int i=0;i<n;i++)scanf("%d",&a[i]);
        int k=0;
        for(int i=0;i<n;i++)
            for(int j=i+1;j<n;j++) {
                P[k].x=a[i];
                P[k].y=a[j];
                P[k++].sum=a[i]+a[j];
            }
        sort(P,P+k,cmp);
        int l=0,r=k-1;
        int flag=0;
        while(l<r){
            if (P[l].sum+P[r].sum==0&&P[l].x!=P[r].x&&P[l].y!=P[r].y&&P[l].x!=P[r].y&&P[l].y!=P[r].x){
                flag = 1;
                break;
            }
            else if(P[l].sum+P[r].sum<0)l++;
            else r--;
        }
        if (flag)printf("Yes
    ");
        else printf("No
    ");
        return 0;
    }
    一种新做法

    E - 和为K的组合(搜索)

     给出N个正整数组成的数组A,求能否从中选出若干个,使他们的和为K。如果可以,输出:"Yes",否则输出"No"。Input第1行:2个数N, K, N为数组的长度, K为需要判断的和(2 <= N <= 20,1 <= K <= 10^9) 
    第2 - N + 1行:每行1个数,对应数组的元素A[i] (1 <= A[i] <= 10^6)Output如果可以,输出:"Yes",否则输出"No"。Sample Input

    5 13
    2
    4
    6
    8
    10

    Sample Output

    No
    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,k,a[30];
    bool flag;
    void dfs(int pos,int sum){
        if(sum==k){
            flag=1;
            return;
        }
        if(pos>=n)return;
        if(flag)return;
        for(int i=pos+1;i<=n;i++)
            dfs(i,sum+a[i]);
    }
    int main(){
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        if(k==0){
            printf("Yes");
            return 0;
        }
        dfs(0,0);
        if(flag){
            printf("Yes");
            return 0;
        }
        else printf("No");
        return 0;
    }
    AC代码 直接深搜

    F - 数组中和等于K的数对(枚举+二分)

    给出一个整数K和一个无序数组A,A的元素为N个互不相同的整数,找出数组A中所有和等于K的数对。例如K = 8,数组A:{-1,6,5,3,4,2,9,0,8},所有和等于8的数对包括(-1,9),(0,8),(2,6),(3,5)。
     

    Input第1行:用空格隔开的2个数,K N,N为A数组的长度。(2 <= N <= 50000,-10^9 <= K <= 10^9)
    第2 - N + 1行:A数组的N个元素。(-10^9 <= A[i] <= 10^9)Output第1 - M行:每行2个数,要求较小的数在前面,并且这M个数对按照较小的数升序排列。 
    如果不存在任何一组解则输出:No Solution。Sample Input

    8 9
    -1
    6
    5
    3
    4
    2
    9
    0
    8

    Sample Output

    -1 9
    0 8
    2 6
    3 5
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int k,n,a[50010];
    bool flag;
    int main(){
        //freopen("Cola.txt","r",stdin);
        scanf("%d%d",&k,&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        sort(a+1,a+1+n);
        for(int i=1;i<n;i++){
            int l=i+1,r=n;
            int x=k-a[i];
            int pos=lower_bound(a+i+1,a+n+1,x)-a;
            if(a[pos]!=x)continue;
            else printf("%d %d
    ",a[i],a[pos]),flag=1;
        }
        if(!flag){
            printf("No Solution");
            return 0;
        }
        return 0;
    }
    AC代码 枚举+二分

    G - 活动安排问题(贪心&线段覆盖)

     有若干个活动,第i个开始时间和结束时间是[Si,fi),同一个教室安排的活动之间不能交叠,求要安排所有活动,最少需要几个教室?  
    Input第一行一个正整数n (n <= 10000)代表活动的个数。 
    第二行到第(n + 1)行包含n个开始时间和结束时间。 
    开始时间严格小于结束时间,并且时间都是非负整数,小于1000000000Output一行包含一个整数表示最少教室的个数。Sample Input

    3
    1 2
    3 4
    2 9

    Sample Output

    2
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 10010
    using namespace std;
    int n;
    bool vis[maxn];
    struct node{
        int s,t;
        bool operator < (const node b)const{
            return t>b.t;
        }
    }a[maxn];
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d%d",&a[i].s,&a[i].t);
        sort(a+1,a+n+1);
        memset(vis,0,sizeof(vis));
        int ans=0;
        while(1){
            int p,st;
            bool flag=0;
            for(int i=1;i<=n;i++){
                if(!vis[i]){
                    p=i;
                    vis[p]=1;
                    flag=1;
                    break;
                }
            }
            if(!flag)break;
            ans++;st=p;
            for(int i=st+1;i<=n;i++){
                if(!vis[i]&&a[i].t<=a[p].s){
                    vis[i]=1;
                    p=i;
                }
            }
        }
        printf("%d",ans);
        return 0;
    }
    AC代码 贪心

    H - Anigram单词(唯一分解定理)

     一个单词a如果通过交换单词中字母的顺序可以得到另外的单词b,那么定义b是a的Anigram,例如单词army和mary互为Anigram。现在给定一个字典,输入Q个单词,从给出的字典中找出这些单词的Anigram。

     

    Input第1行:1个数N,表示字典中单词的数量。(1 <= N <= 10000) 
    第2 - N + 1行,字典中的单词,单词长度 <= 10。 
    第N + 2行:查询的数量Q。(1 <= Q <= 10000) 
    第N + 3 - N + Q - 2行:用作查询的单词,单词长度 <= 10。Output共Q行,输出Anigram的数量,相同的2个单词不算Anigram,如果没有输出0。Sample Input

    5
    add
    dad
    bad
    cad
    did
    3
    add
    cac
    dda
    

    Sample Output

    1
    0
    2
    /*
        首先定义a-z分别为从1开始的素数,例如a=2,b=3,c=5,d=7这样.
        然后定义一个函数int Func(char* data)
        然后函数里面对于每个单词的每个字母进行相乘,例如单词abc就等于5*2*3=30;返回30
        然后再到字典里面去找与这个单词位数相同且Func返回值相同的单词就好了.
        
        这个算法主要用到了一个数学界的定理,如果一个正整数是n个素数相乘的结果,那么这个正整数有且只有一组素数解.
        定理证明过程
        z = a1*a2*....*an.
        用反证法,如果有解,那么
        z = a1*a2*.....*an-2*b*c,(b c代表如果有其它解的情况)两式相除得到下面的
        
        对于这个题来说,还要将答案减去字典中与该字符串相等的字符串个数 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<map>
    using namespace std;
    int su[100],cnt,n;
    map<string,int>q1;
    map<long long,int>q2;
    bool vis[200];
    int main(){
        scanf("%d",&n);
        for(int i=2;i<=100;i++){
            if(!vis[i])su[++cnt]=i;
            for(int j=1;j<=cnt&&su[j]*i<=100;j++){
                vis[su[j]*i]=1;
                if(i%su[j]==0)break;
            }
        }
        long long ans=1;
        string s;
        for(int i=1;i<=n;i++){
            cin>>s;
            q1[s]++;
            int len=s.length();
            long long num=1;
            for(int j=0;j<len;j++){
                int x=s[j]-'a'+1;
                num*=x;
            }
            q2[num]++;
        }
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            cin>>s;
            int ans=0;
            int len=s.length();
            long long num=1;
            for(int j=0;j<len;j++){
                int x=s[j]-'a'+1;
                num*=x;
            }
            ans=q2[num]-q1[s];
            printf("%d
    ",ans);
        }
    }
    AC代码 唯一分解定理

    I - 全排列 (搜索)

    给出一个字符串S(可能有重复的字符),按照字典序从小到大,输出S包括的字符组成的所有排列。例如:S = "1312",
    输出为:
     
    1123
    1132
    1213
    1231
    1312
    1321
    2113
    2131
    2311
    3112
    3121
    3211

    Input输入一个字符串S(S的长度 <= 9,且只包括0 - 9的阿拉伯数字)Output输出S所包含的字符组成的所有排列Sample Input

    1312

    Sample Output

    1123
    1132
    1213
    1231
    1312
    1321
    2113
    2131
    2311
    3112
    3121
    3211
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<map>
    #define maxn 10
    using namespace std;
    int q[maxn],n,a[maxn];
    char s[maxn];
    bool vis[maxn];
    map<string,int>v;
    void dfs(int pos){
        if(pos==n+1){
            string c="";
            for(int i=1;i<=n;i++)c+=a[i]+'0';
            if(v[c])return;
            v[c]=1;
            for(int i=1;i<=n;i++)printf("%d",a[i]);
            puts("");
            return;
        }
        for(int i=1;i<=n;i++){
            if(!vis[i]){
                vis[i]=1;
                a[pos]=q[i];
                dfs(pos+1);
                vis[i]=0;
            }
        }
    }
    int main(){
        scanf("%s",s+1);
        n=strlen(s+1);
        for(int i=1;i<=n;i++)q[i]=s[i]-'0';
        sort(q+1,q+n+1);
        dfs(1);
    }
    75分 暴力
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int a[11],n;
    char s[11];
    int main(){
        scanf("%s",s);
        n=strlen(s);
        for(int i=0;i<n;i++)a[i]=s[i]-'0';
        sort(a,a+n);
        do{
            for(int i=0;i<n;i++)cout<<a[i];
            cout<<endl;
        }while(next_permutation(a,a+n));
    }
    100分 next_permutation

    J - 旋转字符串 (STL)

    S[0...n-1]是一个长度为n的字符串,定义旋转函数Left(S)=S[1…n-1]+S[0].比如S=”abcd”,Left(S)=”bcda”.一个串是对串当且仅当这个串长度为偶数,前半段和后半段一样。比如”abcabc”是对串,”aabbcc”则不是。

    现在问题是给定一个字符串,判断他是否可以由一个对串旋转任意次得到。


    Input第1行:给出一个字符串(字符串非空串,只包含小写字母,长度不超过1000000)Output对于每个测试用例,输出结果占一行,如果能,输出YES,否则输出NO。Sample Input

    aa
    ab

    Sample Output

    YES
    NO
    /*
        对串无论旋转多少次都是对串,所以直接判断当前字符串是否是对串即可 
    */
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    string s;
    int main(){
        while(cin>>s){
            int l=s.length();
            if(l%2!=0){
                puts("NO");
                continue;
            }
            l/=2;
            string s1=s.substr(0,l);
            string s2=s.substr(l,l);
            if(s1==s2)puts("YES");
            else puts("NO");
        }
        return 0;
    }
    100分

    K - 畅通工程 (Tarjan)

    某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路? 

    Input测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。 
    注意:两个城市之间可以有多条道路相通,也就是说 
    3 3 
    1 2 
    1 2 
    2 1 
    这种输入也是合法的 
    当N为0时,输入结束,该用例不被处理。 
    Output对每个测试用例,在1行里输出最少还需要建设的道路数目。 
    Sample Input

    4 2
    1 3
    4 3
    3 3
    1 2
    1 3
    2 3
    5 2
    1 2
    3 5
    999 0
    0

    Sample Output

    1
    0
    2
    998
    /*
        答案=强联通分量个数-1 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 1010
    #define min(a,b) (a)<(b)?(a):(b)
    using namespace std;
    int n,m,num,head[maxn];
    struct node{
        int to,pre;
    }e[maxn*maxn];
    void Insert(int from,int to){
        e[++num].to=to;
        e[num].pre=head[from];
        head[from]=num;
    }
    int dfn[maxn],low[maxn],st[maxn],top,cnt;
    bool in[maxn];
    bool Tarjan(int u){
        cnt++;dfn[u]=low[u]=cnt;st[++top]=u;in[u]=1;
        for(int i=head[u];i;i=e[i].pre){
            int v=e[i].to;
            if(!dfn[v]){
                Tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(in[v])low[u]=min(low[u],dfn[v]);
        }
        if(dfn[u]==low[u]){
            while(st[top]!=u){
                in[st[top]]=0;
                top--;
            }
            in[u]=0;
            top--;
        }
    }
    int main(){
        while(1){
            memset(in,0,sizeof(in));
            memset(dfn,0,sizeof(dfn));
            memset(low,0,sizeof(low));
            memset(head,0,sizeof(head));
            memset(e,0,sizeof(e));
            num=0;cnt=0;
            scanf("%d",&n);
            if(n==0)return 0;
            scanf("%d",&m);
            int x,y;
            for(int i=1;i<=m;i++){
                scanf("%d%d",&x,&y);
                Insert(x,y);Insert(y,x);
            }
            int sum=0;
            for(int i=1;i<=n;i++){
                if(!dfn[i]){
                    sum++;
                    Tarjan(i);
                }
            }
            printf("%d
    ",sum-1);
        }
    }
    100分 Tarjan
  • 相关阅读:
    年近30,朋友聚会都聊什么?
    2016世界最热门的编程语言与薪资揭秘
    程序员的春天来了,最美赏花旅游地十大攻略
    雄联盟工程师独家分享:如何使开发更有效率
    小偷被抓叫嚣:我不偷警察没饭吃
    3.7女生节:被程序员男友送的奇葩礼物宠哭了
    最适合程序员加班吃的6大营养美食
    谷歌汽车出误判曝光 6大奇葩科技更牛
    【程序员的爱情】彼岸花开谁又种下了执念
    分享10个免费或便宜的Photoshop替代工具
  • 原文地址:https://www.cnblogs.com/thmyl/p/7527590.html
Copyright © 2011-2022 走看看