1. 程式人生 > >(寒假GYM開黑)2018 German Collegiate Programming Contest (GCPC 18)

(寒假GYM開黑)2018 German Collegiate Programming Contest (GCPC 18)

spa lse 構造 expire void 所有 www. .html bits


layout: post
title: 2018 German Collegiate Programming Contest (GCPC 18)
author: "luowentaoaa"
catalog: true
tags:
mathjax: true
- codeforces


傳送門

付隊博客

C.Coolest Ski Route (記憶化搜索)

題意

給出一個有向圖,求出一個權值最長的鏈,

題解

暴力dfs會超時,所以直接儲存每個起點能走到的最遠距離

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int maxn=1e3+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
int n,m;
struct node{
    int v,c;
};
vector<node>G[maxn];
int dp[maxn];
int dfs(int now){
    if(dp[now]!=-1)return dp[now];
    int ans=0;
    for(auto i:G[now]){
        ans=max(ans,dfs(i.v)+i.c);
    }
    return dp[now]=ans;
}
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    cin>>n>>m;
    memset(dp,-1,sizeof(dp));
    for(int i=1;i<=m;i++){
        int x,y,z;
        cin>>x>>y>>z;
        G[x].push_back(node{y,z});
    }
    int mx=-inf;
    for(int i=1;i<=n;i++){
        if(dp[i]==-1){
            mx=max(mx,dfs(i));
        }
    }
    cout<<mx<<endl;
    return 0;
}

D.Down the Pyramid (不等式)

題意

金字塔的每一層都比上一層多一個,並且上一層的值是下一層的兩個相鄰之和

給出第n層,讓你求出第N+1層的值有多少種可能性(需要保證每一個數都大於等於0)

題解

比賽一直想不出,付隊做的.想法是,

假設給出的值是a1,a2,a3,a4,

假設第一個位置(b1)是X,那麽第二個位置(b2)的值就是a1-x,第三個位置的值就是a2-(a1-x);

可以發現都和第一個假設的位置的值x有關,所以我們只要保證這個過程每個位置的值都大於0就可以求出X的可能取值

a1-x>=0 a2-a1-x>=0 ->x<=a1 x<=a2-a1;

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int maxn=1e6+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
int a[maxn];

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    int ans=0;
    int mi=0,mx=a[1];
    for(int i=1;i<=n;i++){
        ans=a[i]-ans;
        if(i&1)mx=min(mx,ans);
        else mi=max(mi,-ans);
    }
    if(mx<mi)cout<<0<<endl;
    else cout<<mx-mi+1<<endl;
    return 0;
}

Expired License (線性篩)

題意

給定你兩個最多帶5位小數的double型a,b,讓你用用一對素數x y表示他們的比值。

題解

先把double變成整數型;註意四舍五入;然後求一下gcd 判斷化簡後是否都是素數即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int maxn=1e7+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-7;
bool check[maxn];
int phi[maxn];
int prime[maxn];
int tot;
void phi_and_prime_table(int N){
    memset(check,false,sizeof(check));
    phi[1]=1;
    tot=0;
    for(int i=2;i<=N;i++){
        if(!check[i]){
            prime[tot++]=i;
            phi[i]=i-1;
        }
        for(int j=0;j<tot;j++){
            if(i*prime[j]>N)break;
            check[i*prime[j]]=true;
            if(i%prime[j]==0){
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            else{
                phi[i*prime[j]]=phi[i]*(prime[j]-1);
            }
        }
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int n,m;
    int t;
    phi_and_prime_table(10000000+10);
    check[1]=true;
    cin>>t;
    while(t--){
        double a,b;
        cin>>a>>b;
        int C=(int)((a+eps)*100000),D=(int)((b+eps)*100000);
        int gc=__gcd(C,D);
        C/=gc;D/=gc;
        if(!check[C]&&!check[D])cout<<C<<" "<<D<<endl;
        else if(C==1&&D==1)cout<<"2 2"<<endl;
        else
            cout<<"impossible"<<endl;
    }
    return 0;
}

F.Fighting Monsters (打表找規律)

題意

給出N個怪獸,問是否選擇兩個怪獸根據題意戰鬥之後 活下來的那個怪剩下一滴血

題解

根據題意打表後發現選擇的兩個怪獸血量必須符合斐波那契數列的相鄰兩項值

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int maxn=1e7+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
int m[maxn];
bool isok(int a,int b){
    int aa=a,bb=b;
    int i=1;
    while(aa>0&&bb>0){
        if(i&1)aa-=bb;
        else bb-=aa;
        i++;
    }
    if(aa==1||bb==1)cout<<"a="<<a<<" b="<<b<<endl;
    aa=a,bb=b;
    i=1;
    while(aa>0&&bb>0){
        if(i&1)bb-=aa;
        else aa-=bb;
        i++;
    }
    if(aa==1||bb==1)cout<<"a="<<a<<" b="<<b<<endl;
}
int F[maxn];
int num[maxn];
int id[maxn];
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
   /* for(int i=1;i<=1000;i++){
        for(int j=i;j<=1000;j++){
            isok(i,j);
        }
    }*/
    F[1]=F[2]=1;
    for(int i=3;i<=31;i++){
        F[i]=F[i-1]+F[i-2];
       // cout<<F[i]<<endl;
    }
    int n;
    cin>>n;
    int flag=0,one;
    for(int i=1;i<=n;i++){
        cin>>m[i];
        if(!flag&&m[i]==1)flag=1,one=i;
        num[m[i]]++;
        id[m[i]]=i;
    }
    int f=0;
    if(num[1]>=2){
        cout<<one<<" "<<id[1]<<endl;
        return 0;
    }
    for(int i=2;i<=30;i++){
        if(num[F[i]]&&num[F[i+1]]){
            f=1;
            cout<<id[F[i]]<<" "<<id[F[i+1]]<<endl;
            break;
        }
    }
    if(!f)cout<<"impossible"<<endl;
    return 0;
}

H.Hyper Illuminati

題意

給定一個數N(<1e16),問是否存在n和s,滿足1^n+2^n+3^n+...s^n=N;輸出n+1,s

題解

slove by 付隊,

如果2<=n<=53,我們發現s不會太大,我們可以把所有的都求出來;如果n>53,則有s<=2,我們可以把s=2的值都求出來。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int maxn=1e7+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    ll ans=0,n;
    cin>>n;
    for(int i=2;i<=53;i++){
        ans=0;
        for(ll j=1;j<=n;j++){
            ll tmp=1;
            for(ll k=1;k<=i;k++){
                if(tmp>n/j){tmp=n+1;break;}
                tmp*=j;
            }
            if(tmp>n)break;
            ans+=tmp;
            if(ans==n)return cout<<i+1<<" "<<j<<endl,0;
            if(ans>n)break;
        }
    }
    ll tmp=1;
    for(ll j=1;j<=n;j++){
        tmp*=2LL;
        if(j>=2){
            if(tmp+1==n)return cout<<j+1<<" "<<2<<endl,0;
        }
        if(tmp+1>=n)break;
    }
    cout<<"impossible"<<endl;
    return 0;
}

I.It‘s Time for a Montage (枚舉暴力)

題意

就是兩邊按順序打架,如果當前相等就比下一個 直到比出勝負,但是主角可以選擇每回合所有怪增加1點攻擊,如果最後沒怪並且主角攻擊大於等於另一個就贏 ,問主角最少需要等多少回合;

題意

因為攻擊力最大值只有1000 所以直接枚舉暴力就行

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int maxn=1e3+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
int h[maxn];
int v[maxn];
int isok(int x,int n){
    for(int i=1;i<=n;i++){
        if(h[i]-v[i]+x==0)continue;
        else if(h[i]-v[i]+x>0)return true;
        else return false;
    }
    return true;
}
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)cin>>h[i];
    for(int i=1;i<=n;i++)cin>>v[i];
    int ans=0;
    for(int i=0;i<=1000;i++){
        if(isok(i,n)){
            cout<<i<<endl;
            return 0;
        }
    }
    return 0;
}

Logic Puzzle

題意

:給你一個大格子,然後在中心格子填黑點,每個格子中有顯示以它為中心的3*3格子有多少個黑點,讓你構造中心格子的黑點, (就是掃雷

題解

從左上開始枚舉對應的雷都是固定的,所以直接掃過去判斷是否可以掃完就行

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int maxn=1e6+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
int dx[9]={0,0,0,1,-1,1,1,-1,-1};
int dy[9]={0,1,-1,0,0,1,-1,1,-1};
int a[150][150],vis[150][150];

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int n,m;
    cin>>n>>m;
    for(int i=0;i<=n+1;i++)for(int j=0;j<=m+1;j++)cin>>a[i][j];
    for(int i=0;i<=n;i++){
        for(int j=0;j<=m;j++){
            if(a[i][j]==1){
                vis[i+1][j+1]=1;
                for(int k=0;k<=8;k++){
                    if(i+1+dx[k]>=0&&i+1+dx[k]<=n+1&&j+1+dy[k]>=0&&j+1+dy[k]<=m+1)
                        a[i+1+dx[k]][j+1+dy[k]]--;
                }
            }
        }
    }
    for(int i=0;i<=n+1;i++)for(int j=0;j<=m+1;j++){
        if(a[i][j]){
            cout<<"impossible"<<endl;return 0;
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(vis[i][j])cout<<"X";
            else cout<<".";
        }
        cout<<endl;
    }
    return 0;
}

(寒假GYM開黑)2018 German Collegiate Programming Contest (GCPC 18)