Gym .102021 .German Collegiate Programming Contest (GCPC 18)

C .Coolest Ski Route

题意:给定带边权有向图,让你找一个最长的链,满足买个点最多遍历一次。

分析:记忆化搜索即可。

代码(by 胡):

#include<bits/stdc++.h>
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define P pair<int,int>
#define INF 1e18
using namespace std;
const int maxn = 200005;
vector<pair<int,int> > G[maxn];
int u[maxn],v[maxn],a[maxn],vis[maxn],d[maxn];
int dp(int x,int fa){
    if(d[x]>0) return d[x];
    for(auto y:G[x]){
        if(y.first==fa) continue;
        dp(y.first,x);
        d[x]=max(d[x],d[y.first]+y.second);
    }
    return d[x];
}
int main(){
    int n,m;
    scanf("%d %d",&n,&m);
    while(m--){
        int u,v,w;
        scanf("%d %d %d",&u,&v,&w);
        G[u].push_back({v,w});
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        ans=max(ans,dp(i,-1));
    }
    cout<<ans<<endl;
    return 0;
}

D .Down the Pyramid

题意:金字塔的每一层的位置的值=下一层的两个值之和,现在给你最倒数第二层的值a1,a2...an,问你最后一层有多少种情况,满足所有数不小于0。被简单题卡了,当时就应该换一种思路。

分析:我们假设第一个位置位b0=x,那么b1=a1-x; b2=a2-b1=a2-a1+x.. 中间给限制让所有数大于等于0,则有x<=a1; x>=a1-a2; x<=a3+a2-a1 ; x>=...。

代码(by 胡):

#include<bits/stdc++.h>
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define P pair<int,int>
#define INF 1e18
using namespace std;
const int maxn = 1000005;
ll a[maxn];
int main(){
    int n;
    cin>>n;
    ll sum=0;
    ll Max,Min;
     for(int i=1;i<=n;i++){
        scanf("%I64d",&a[i]);
        if(i==1){
            Max=a[1];
            Min=0;
        }
        sum=a[i]-sum;
        if(i%2==0) Min=max(Min,-sum);
        else Max=min(Max,sum);
    }
    if(Min>Max) return puts("0")*0;
    cout<<Max-Min+1<<endl;
    return 0;
}

E .Expired License

题意:给定你两个最多带5位小数的double型a,b,让你用用一对素数x y表示他们的比值。

思路:我们把a和b都乘1e5、除以gcd,再验证是否是素数即可。 注意特判1,1的情况(答案是2 2)。

代码(by 胡):

#include<bits/stdc++.h>
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define P pair<int,int>
#define INF 1e18
using namespace std;
const int maxn = 20000005;
bool check[maxn];
int prime[2000005];
int tot;
void init(){
    check[1]=1;
     for(int i=2;i<maxn;++i) {
        if(!check[i]) prime[tot++] = i;
        for(int j=0;j<tot;j++){
            if(i*prime[j]>maxn) break;
            check[i*prime[j]] = 1;
            if (i%prime[j] == 0 ) break;
        }
    }
}
int main(){
   int t;
   init();
   cin>>t;
   char s1[10],s2[10];
   while(t--){
        scanf("%s %s",s1,s2);
        ll a=0;
        ll b=0;
        int len=strlen(s1);
        int fg1=0,fg2=0;
        int pos1=0,pos2=0;
        for(int i=0;i<len;i++){
            if(s1[i]=='.') {
                pos1=1;
                continue;
            }
            else{
                a=a*10+s1[i]-'0';
                if(pos1) fg1++;
            }
        }
        len=strlen(s2);
        for(int i=0;i<len;i++){
            if(s2[i]=='.') {
                pos2=1;
                continue;
            }
            else{
                b=b*10+s2[i]-'0';
                if(pos2) fg2++;
            }
        }
        if(fg1>fg2){
            fg2=fg1-fg2;
            while(fg2){
                b*=10;
                fg2--;
            }
        }else if(fg2>fg1){
            fg1=fg2-fg1;
            while(fg1){
                a*=10;
                fg1--;
            }
        }
        ll gcd=__gcd(a,b);
        a=a/gcd;
        b=b/gcd;
        if(a==1&&b==1){
            puts("2 2");
            continue;
        }
        if(!check[a]&&!check[b]) printf("%I64d %I64d\n",a,b);
        else puts("impossible");
   }
   return 0;
}

F .Fighting Monsters

题意:给定N个怪兽,问是否能选处两个怪兽,使得他们相互攻击,最后活着的怪兽剩1滴血。

分析:判断是否存在相邻的Fibonacci数。

代码(by 胡):

#include<bits/stdc++.h>
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define P pair<int,int>
#define INF 1e18
using namespace std;
const int maxn = 1000005;
int x[maxn];
int pos[maxn];
int a[maxn];
int main(){
    a[1]=1;
    a[2]=1;
    for(int i=3;i<=32;i++){
        a[i]=a[i-1]+a[i-2];
    }
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%d",&x[i]);
    }
    int a1,b1;
    for(int i=1;i<=32;i++){
        a1=0;
        b1=0;
        for(int j=1;j<=n;j++){
            if(x[j]==a[i]){
                a1=j;
                break;
            }
        }
        for(int j=1;j<=n;j++){
            if(j==a1) continue;
            if(x[j]==a[i+1]){
                b1=j;
                break;
            }
        }
        if(a1&&b1){
            cout<<a1<<" "<<b1<<endl;
            return 0;
        }
    }
    puts("impossible");
    return 0;
}

H .Hyper Illuminati

题意:给定一个数N(<1e16),问是否存在n和s,满足1^n+2^n+3^n+...s^n=N;输出n+1,s;

思路:2^54>1e16,n的范围很小,暴力就好了

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll ans=0,m;
int main(){
    scanf("%lld",&m);
    for(ll i=2;i<=54;i++) {
        ans=0;
        for(ll j=1;j<=m;j++){
            ll tp=1;
            for(ll k=1;k<=i;k++) {
                 if(tp>m/j) {
                    tp=m+1;
                    break;
                 }
                 tp*=j;
            }
            if(tp>m) break;
            ans+=tp;
            if(ans==m) {
                printf("%lld %lld\n",i+1,j);
                return 0;
            }
            else if(ans>=m) break;
        }
    }
    printf("impossible\n");
    return 0;
}

I .It's Time for a Montage

水题

L. Logic Puzzle

题意:扫雷,复原雷图。

思路:从左上顶点开始,如果一个点a[i][j]=1,那么a[i+1][j+1]一定是雷,然后把周围9个点都-1;最后遍历一遍,全是0就输出雷的排列,否则输出impossible。

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=110;
int n,m,a[N][N],vis[N][N];
int x[9]= {1,1,1,-1,-1,-1,0,0,0};
int y[9]= {1,-1,0,1,-1,0,1,-1,0};

int main() {
    scanf("%d%d",&n,&m);
    for(int i=0;i<=n+1;i++)
        for(int j=0;j<=m+1;j++)
            scanf("%d",&a[i][j]);
    for(int i=0;i<=n;i++) {
        for(int j=0;j<=m;j++) {
            if(a[i][j]) {
                vis[i+1][j+1]=1;
                for(int k=0;k<9;k++) {
                    if(i+1+x[k]>=0&&i+1+x[k]<=n+1&&j+1+y[k]>=0&&j+1+y[k]<=m+1)
                        a[i+1+x[k]][j+1+y[k]]--;
                }
            }
        }
    }
    for(int i=0;i<=n+1;i++) {
        for(int j=0;j<=m+1;j++)
            if(a[i][j]) {
                printf("impossible\n");
                return 0;
            }
    }
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=m;j++)
            if(vis[i][j]) printf("X");
            else printf(".");
        printf("\n");
    }
    return 0;
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值