zoukankan      html  css  js  c++  java
  • 2018 German Collegiate Programming Contest (GCPC 18)_组队训练

    2018 German Collegiate Programming Contest (GCPC 18)

    A Attack on Alpha-Zet

    B Battle Royale

    C Coolest Ski Route

    D Down the Pyramid

    E Expired License

    F Fighting Monsters

    H Hyper Illuminati

    I It’s Time for a Montage

    K Kitchen Cable Chaos

    L Logic Puzzle

    M Mountaineers
    A Attack on Alpha-Zet
    题意:给你一个迷宫,并给你几个点,让你求最短路径。
    题解:lca裸题,直接带板子。
    #include<bits/stdc++.h>
    #define ll long long int
    #define mem(a,b) memset(a,b,sizeof a)
    using namespace std;
    const int maxn = 3030;
    char mp[maxn][maxn];
    bool vis[maxn*maxn];
    int n,m,q,dis[maxn*maxn],fa[3001000][25];
    typedef pair<int,int> pp;
    vector<pp>v;
    vector<int>v2[maxn*maxn];
    int getval(int x,int y) 
    {
        return (x-1)*(m*2+1) + y*2;
    }
    
    void build_tree() 
    {
        for(int i=2;i<=n+1;i++) 
        {
            for(int j=2;j<=m*2;j+=2) 
            {
                if(mp[i][j] == ' ') 
                {
                    v2[getval(i, j)].push_back(getval(i+1, j));
                    v2[getval(i+1, j)].push_back(getval(i, j));
                }
                if(mp[i][j+1] != '|') 
                {
                    v2[getval(i, j)].push_back(getval(i, j+2));
                    v2[getval(i, j+2)].push_back(getval(i, j));
                }
            }
            //cout<<i<<endl;
        }
        //cout<<1<<endl;
    }
    void dfs(int prev,int rt)
    {
        //cout<<prev<<endl;
        /*if(vis[prev] == 1)
        {
            return;
        }
        vis[prev] = 1;*/
        dis[rt]=dis[prev]+1;
        fa[rt][0]=prev;
        for (int i=1;i<20;i++)
            fa[rt][i]=fa[fa[rt][i-1]][i-1];
        for (int i=0;i<v2[rt].size();i++) {
            if(prev == v2[rt][i]) continue;
            dfs(rt, v2[rt][i]);
        }
    }
    
    int LCA(int x,int y)
    {
        //cout<<x<<endl;
        if (dis[x]<dis[y])
            swap(x,y);
        for (int i=19;i>=0;i--)
            if (dis[x]-(1<<i)>=dis[y])
                x=fa[x][i];
        if (x==y)
            return x;
        for (int i=19;i>=0;i--)
            if (fa[x][i]!=fa[y][i])
                x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    
    int main()
    {
        cin>>n>>m;
        getchar();
        for(int i=1;i<=n+1;i++)
        {
            gets(mp[i]+1);
            //cout<<i<<endl;
        }
        //cout<<1<<endl;
        /*for(int i=1;i<=n+1;i++)
        {
            cout<<mp[i]+1<<endl;
        }*/
        int q;
        cin>>q;
        for(int i=1;i<=q;i++)
        {
            int a,b;
            cin>>a>>b;
            v.push_back(make_pair(a,b));
        }
        build_tree();
        //cout<<1<<endl;
        int xx = getval(v[0].first+1, v[0].second*2);
        //cout<<xx<<endl;
        dfs(0, xx);
        ll ans = 0;
        for(int i=0;i<v.size()-1;i++) 
        {
            int x = v[i].first;
            int y = v[i].second;
            int num1 = getval(x+1, y*2);
            x = v[i+1].first;
            y = v[i+1].second;
            int num2 = getval(x+1, y*2);
            ans += dis[num1] + dis[num2] - dis[LCA(num1, num2)] * 2;
            //cout<<i<<endl;
        }
        printf("%lld
    ", ans);
        return 0;
    }
    B Battle Royale
    题意:给两个圈,一里一外,再在两个圈中间给两个点,求这两点不通过里面那圈的最短距离。
    题解:那就是从两点向内圈射出两条切线,然后加上切点之间的弧长就好了。
    #include<bits/stdc++.h>
    #define ll long long int
    #define pi acos(-1.0)
    using namespace std;
    const double precision = 1e-7;
    int main()
    {
        double xc,yc,xd,yd,xb,yb,rb,xr,yr,rr;
        cin>>xc>>yc>>xd>>yd>>xb>>yb>>rb>>xr>>yr>>rr;
        if(xc==xd&&yc==yd)
        {
            puts("0.0000000");
            return 0;
        }
        double d = 0;
        if(xd == xc&&yc != yd)
        {
            d = abs(xc-xr);
        }
        else{
            d = fabs((yd-yc)*1.0/(xd-xc)*(xr-xc)+yc-yr)/(sqrt((yd-yc)*(yd-yc)*1.0/(xd-xc)/(xd-xc)+1));
        }
        //cout<<d<<endl;
        double xx;
        if(d>=rr)
        {
            xx = sqrt((yc-yd)*(yc-yd)+(xc-xd)*(xc-xd));
            printf("%.7lf",xx);
        }
        else{
            double x1 = sqrt((xd-xr)*(xd-xr)+(yd-yr)*(yd-yr)-rr*rr);
            double x2 = sqrt((xc-xr)*(xc-xr)+(yc-yr)*(yc-yr)-rr*rr);
            //cout<<x1<<" "<<x2<<endl;
            double xx1 = asin(rr/(sqrt((xd-xr)*(xd-xr)+(yd-yr)*(yd-yr))));
            double xx2 = asin(rr/(sqrt((xc-xr)*(xc-xr)+(yc-yr)*(yc-yr))));
            //cout<<xx1<<" "<<xx2<<endl;
            xx1 = pi/2 - xx1;
            xx2 = pi/2 - xx2;
            double A = acos(((xd-xr)*(xd-xr)+(yd-yr)*(yd-yr)+(xc-xr)*(xc-xr)+(yc-yr)*(yc-yr)-((yc-yd)*(yc-yd)+(xc-xd)*(xc-xd)))/(2*sqrt((xd-xr)*(xd-xr)+(yd-yr)*(yd-yr))*sqrt((xc-xr)*(xc-xr)+(yc-yr)*(yc-yr))));
            double B = A - xx1 - xx2;
            //cout<<B<<endl;
            double pp = B*rr;
            //cout<<pp<<endl;
            printf("%.7lf
    ",pp+x1+x2);
        }
     } 
    C Coolest Ski Route
    题意:给你n个点,和m条单向路,求最长的路径。
    题解:dfs一遍,不过会超时,所以我们需要把最大值存一下优化一下,来减少dfs的层数。
    #include<bits/stdc++.h>
    #define ll long long int
    #define mem(a,b) memset(a,b,sizeof a)
    using namespace std;
    vector<int>v[1010];
    int mp[1010][1010];
    int dist[1010];
    bool vis[1010];
    int n,m;
    int dfs(int step)
    {
        if(vis[step]) return dist[step];
        for(int i=0;i<v[step].size();i++)
        {
            dist[step]=max(dist[step],dfs(v[step][i])+mp[step][v[step][i]]);
        }
        vis[step] = 1;
        return dist[step];
    }
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=m;i++)
        {
            int s,t,c;
            cin>>s>>t>>c;
            v[s].push_back(t);
            mp[s][t] = max(mp[s][t],c);
        }
        int maxx = 0;
        for(int i=1;i<=n;i++)
        {
            maxx = max(maxx,dfs(i));
        }
        cout<<maxx<<endl;
    }

    D Down the Pyramid

    题意:给你一个数字金字塔,金子塔上的数字为下面左下和右下的两数之和,现在给你一排金字塔的数,求下面一排金字塔的数可以有多少种。

    题解:我们可以把下一行金字塔的第一个定为0,然后求出符合规则的这一行,因为我们知道这一行1,3,5,7......位如果增加1的话,2,4,6,8...位就会减少1

    所以为了满组所有最小为0,那么我们看一下1,3,5,7...位最小需要加多少才可以到达0,而2,4,6,8....最多可以减多少到达0,他们的差值就是了。

    #include<bits/stdc++.h>
    #define ll long long int
    #define mem(a,b) memset(a,b,sizeof a)
    using namespace std;
    ll a[1001000];
    ll b[1000100];
    int main()
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        b[1] = 0;
        int ans = 2;
        for(int i=1;i<=n;i++)
        {
            b[ans] = a[i] - b[ans-1];
            ans++;
        }
        /*for(int i=1;i<ans;i++)
        {
            cout<<b[i]<<" ";
        }
        cout<<endl;*/
        ll minn = 0;
        for(int i=1;i<ans;i+=2)
        {
            if(b[i]<0)
            {
                minn = min(minn,b[i]);
            }
        }
        
        minn = -minn;
        //cout<<minn<<endl;
        ll maxx = 10000000000;
        for(int i=2;i<ans;i+=2)
        {
            if(b[i]-minn<0)
            {
                puts("0");
                return 0;
            }
            else{
                maxx = min(maxx,b[i]-minn+1);
            }
        }
        cout<<maxx<<endl;
    }

    E Expired License

    题意:给你两个实数比看你能不能转化位两个质数比,实数最多为小数点后5位.

    题解:将输入以字符串输入,然后将他们扩大100000倍,求个gcd,一开始用欧拉筛初始化一下,然后判定一下,不过当两个数一样的时候判定一下输出2 2

    #include<bits/stdc++.h>
    #define ll long long int
    #define mem(a,b) memset(a,b,sizeof a)
    using namespace std;
    const int maxn = 1e7+5;
    int prime[maxn];
    int visit[maxn];
    void Prime(){
        mem(visit,0);
        mem(prime, 0);
        for (int i = 2;i <= maxn; i++) {
            //cout<<" i = "<<i<<endl;
            if (!visit[i]) {
                prime[++prime[0]] = i;      //纪录素数, 这个prime[0] 相当于 cnt,用来计数
            }
            for (int j = 1; j <=prime[0] && i*prime[j] <= maxn; j++) {
    //            cout<<"  j = "<<j<<" prime["<<j<<"]"<<" = "<<prime[j]<<" i*prime[j] = "<<i*prime[j]<<endl;
                visit[i*prime[j]] = 1;
                if (i % prime[j] == 0) {
                    break;
                }
            }
        }
    }
    ll change(string s)
    {
     int len = s.length();
     int k = len;
     ll xx = 0;
     for(int i=0;i<len;i++)
     {
      if(s[i]=='.')
      {
       k=i;
       break;
      }
      xx=xx*10+s[i]-'0';
     }
     ll yy = 0;
     int ans = 10000;
     for(int i=k+1;i<len;i++)
     {
      yy +=(s[i]-'0')*ans;
      ans/=10;
     }
     return xx*100000+yy;
    }
    int main()
    {
     int T;
     Prime();
     cin>>T;
     while(T--)
     {
      string a,b;
      cin>>a>>b;
      ll x = change(a);
      ll y = change(b);
      //cout<<x<<" "<<y<<endl;
      ll ans = __gcd(x,y);
      ll c = x/ans;
      ll d = y/ans;
      if(c==d){
          cout<<2<<" "<<2<<endl;
          continue;
      }
      if(visit[c]==0&&visit[d]==0&&c!=1&&d!=1)
      {
       cout<<c<<" "<<d<<endl;
      }
      else{
       puts("impossible");
      }
     }
    }

     Problem F: Fighting Monsters

    题意:让你在一个数组里找到可以最后减为一个0,一个1的两个数。

    题解:由这个性质可以得出最后的两个数为0,1.。。。1,1。。。。1,2.。。。。3.,2。。。3,5,看你看出得到的为两个连续斐波那契数,所以在数组中找就可以

    了。

    #include<bits/stdc++.h>
    #define ll long long int
    #define mem(a,b) memset(a,b,sizeof a)
    using namespace std;
    ll a[1001000];
    ll b[1000100];
    map<int,int>mp;
    map<int,int>mm;
    map<int,int>mo;
    int f[1000100];
    int main()
    {
        int n;
        cin>>n;
        int ans = 0;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            mo[a[i]] = i;
            if(a[i]==1) ans++;
            b[i] = a[i];
        }
        //sort(a+1,a+1+n);
        if(ans>=2)
        {
            int q = 0;
            for(int i=1;i<=n;i++)
            {
                if(a[i]==1)
                {
                    cout<<i<<" ";
                    q++;
                }
                if(q>=2) break;
            }
            return 0;
        }
        bool flag = 0;
        f[1] = 1;
        f[0] = 1;
        mp[1] = 1;
        mm[1] = 0;
        for(int i=2;i<10000;i++)
        {
            f[i] = f[i-1] + f[i-2];
            mp[f[i]] = 1;
            mm[f[i]] = f[i-1];
            if(f[i]>1000000)
            {
                break;
            } 
        }
        for(int i=1;i<=n;i++)
        {
            if(mp[a[i]]&&mo[mm[a[i]]])
            {
                //cout<<mm[a[i]]<<endl;
                if(a[i]<a[mo[mm[a[i]]]])
                    cout<<i<<" "<<mo[mm[a[i]]]<<endl;
                else{
                    cout<<mo[mm[a[i]]]<<" "<<i<<endl;
                }
                flag = 1;
                break;
            }
        }
        if(!flag) puts("impossible");
    }

     H  Hyper Illuminati

    题意:给你一给数字为小方块的总个数,让你求可不可以构成n维s层的金字塔堆。

    题解:由于数字不大,所以暴力枚举就可以了,满足∑ si=1   in-1== m。

    #include<bits/stdc++.h>
    #define ll long long int
    #define mem(a,b) memset(a,b,sizeof a)
    using namespace std;
    const int maxn = 3030;
    long long modexp(long long a, long long b)
    {
        long long res=1;
        while(b>0)
        {
            if(b&1)
                res=res*a;
            b=b>>1;
            a=a*a;
        }
        return res;
    }
    int main()
    {
        ll m;
        cin>>m;
        for(int i=3;i<=60;i++)
        {
            ll sum = 0;
            for(int j=1;;j++)
            {
                sum += modexp(j,i-1);
                if(sum == m)
                {
                    cout<<i<<" "<<j;
                    return 0;
                }
                else if(sum>m)
                {
                    break;
                }
            }
        }
        puts("impossible");
    }

    I  It’s Time for a Montage

    题解:有n个士兵和n个敌人,每个人都有一个力量值,你的人训练一天可以增加一点力量,打仗是这样的:按顺序从1到n,a[i]打b[i],只要a[i]>b[i],你就赢了,a[i]<b[i],你就输了,相等就看下一个,全部相等也算你赢,问你最少要训练几天才可以打败对方。

    题解:可以枚举天数,因为数字不大,直接暴力枚举就行。

    #include<bits/stdc++.h>
    #define ll long long int
    #define mem(a,b) memset(a,b,sizeof a)
    using namespace std;
    const int maxn = 1010;
    const ll mod =   1000000009;
    int h[1010],v[1001],d[1010];
    int main()
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>h[i];
        }
        for(int i=1;i<=n;i++)
        {
            cin>>v[i];
        }
        for(int i=1;i<=n;i++)
        {
            d[i] = h[i]-v[i];
        }
        for(int i=0;i<=1001;i++)
        {
            for(int j=1;j<=n;j++)
            {
                d[j]+=i;
            }
            int ans = 0;
            bool flag = 0;
            for(int j=1;j<=n;j++)
            {
                if(d[j]<0)
                {
                    break;
                }
                if(d[j]>0)
                {
                    flag = 1;
                    break;
                }
                if(d[j]==0)
                {
                    ans++;
                }
            }
            if(ans == n)
            {
                flag = 1;
            }
            if(flag)
            {
                printf("%d
    ",i);
                return 0;
            }
            for(int j=1;j<=n;j++)
            {
                d[j] -= i;
            }
        }
    }

     L Logic Puzzle

    题意:扫雷图复原。

    #include<bits/stdc++.h>
    #define ll long long int
    #define mem(a,b) memset(a,b,sizeof a)
    using namespace std;
    const int maxn = 1010;
    const ll mod =   1000000009;
    int mp[120][120];
    int ans[120][120];
    int main()
    {
        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n+2; i++)
        {
            for(int j=1; j<=m+2; j++)
            {
                cin>>mp[i][j];
            }
        }        
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                if(mp[i][j]>0)
                {
                    ans[i][j]=1;
                    mp[i][j+1]--;mp[i][j]--;mp[i][j+2]--;mp[i+1][j+1]--;mp[i+1][j+2]--;
                    mp[i+1][j]--;mp[i+2][j+1]--;mp[i+2][j+2]--;mp[i+2][j]--;
                }
                else if(mp[i][j]<0)
                {
                    puts("impossible");
                    return 0;
                }
            }
            for(int k=1; k<=m+2; k++)
            {
                if(mp[i][k]!=0)
                {
                    puts("impossible");
                    return 0;
                }
            }
        }
        for(int i=n; i<=n+2; i++)
        {
            for(int j=1; j<=m+2;j++)
            {
                if(mp[i][j]!=0)
                {
                    puts("impossible");
                    return 0;
                }
            }
        }
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                if(ans[i][j]==1)
                    printf("X");
                else
                    printf(".");
            }
            cout<<endl;
        }
        return 0;
    
    }
  • 相关阅读:
    Jdbc 事务
    Spring
    【Java集合的详细研究1】Collections类常用方法总结
    Java Number类
    Java中值类型和引用类型的区别
    Java常量池的理解
    Java重写与重载之间的区别
    Java中Animal b = new Dog();Dog c = new Dog();的区别
    java类构造器的理解
    Javascript history pushState onpopstate方法做AJAX SEO
  • 原文地址:https://www.cnblogs.com/lcsdsg/p/14358835.html
Copyright © 2011-2022 走看看