Fork me on GitHub

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\n", 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\n",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\n",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;

}

 

posted @ 2021-02-04 15:02  lcsdsg  阅读(86)  评论(0编辑  收藏  举报
【推荐】 程序员网址大全  |  EF CodeFirst  |  百度地图.NET  |  MyNPOI  |  开源  |  我的皮肤  |  ASP.NET MVC4  |  前端提升   |  LINQ   |  WCF   |  EasyUI  |