1. 程式人生 > >2018-2019 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2018)

2018-2019 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2018)

傳送門

A.Altruistic Amphibians

    一個挺有意思的題目。首先考慮這樣的問題:倘若要讓儘可能多的青蛙能夠逃跑,則顯然羅漢最好疊得儘可能的高(這才能使得那些不能一次性跳出的青蛙能夠逃離)。

    而顯然,對於那些體重最大的青蛙,他們顯然不能疊在其他青蛙上,因此我們首先對青蛙的重量從大到小進行排序,其次我們考慮第i個青蛙的重量對於其他重量小的重量的青蛙的狀態的轉移。

    我們設dp[i]為重量為i的青蛙最高能夠跳的高度,而對於第i個重量為w[i]的青蛙,不難想到最多一定會有個w[i]個重量小於w[i]的青蛙能夠跳到它的上面,故可得有狀態轉移方程(dp[j-w[i]]=max(dp[j-w[i]],dp[j]+h[i])(w[i]<=j<=2*w[i])

#include <bits/stdc++.h>
#define maxn 100000005
using namespace std;
int dp[maxn];
struct Node{
    int l,w,h;
    bool operator <(const Node &b)const{
        return w>b.w;
    }
}q[100005];
int main()
{
    int n,d;
    scanf("%d%d",&n,&d);
    for(int i=0;i<n;i++) scanf("
%d%d%d",&q[i].l,&q[i].w,&q[i].h); sort(q,q+n); int res=0; for(int i=0;i<n;i++){ if(dp[q[i].w]+q[i].l>d) res++; for(int j=q[i].w;j<min(2*q[i].w,(int)1e8+2);j++){ dp[j-q[i].w]=max(dp[j-q[i].w],dp[j]+q[i].h); } } printf("%d\n",res); }
View Code

 


 B.Baby Bites

    溫暖的簽到題

#include<bits/stdc++.h>
using namespace std;
string str;
int change(string s){
    int len=s.size();
    int ret=0;
    for(int i=0;i<len;i++){
        ret=ret*10+str[i]-'0';
    }
    return ret;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n;
    cin>>n;
    int flag=0;
    for(int i=1;i<=n;i++){
        cin>>str;
        if(str[0]>='0'&&str[0]<='9'){
            int num=change(str);
            if(num!=i) flag=1;
        }
    }
    if(flag) cout<<"something is fishy"<<endl;
    else cout<<"makes sense";;
    return 0;

}
View Code

 


C.Code Cleanups

    題意相當奇怪的簽到題。實際的題意為:給你若干個操作,每個操作的序號id都是遞增的。在第id天一定會進行該次操作。每次進行一次操作,骯髒值就會+1(最開始骯髒值為0),骯髒值每天都累計,直到在某一天,累計的骯髒值大於20,則將所有的骯髒值清零,現在問你最小的清零的次數。

    這個題明白題意後就是一個很簡單的題目了

#include<bits/stdc++.h>
using namespace std;
int mp[400];
int main(){
    int n;
    scanf("%d",&n);
    int tmp;
    for(int i=1;i<=n;i++){
        scanf("%d",&tmp);
        mp[tmp]=1;
    }
    tmp=0;
    int sum=0;
    int ans=0;
    for(int i=1;i<=365;i++){
        if(mp[i]) tmp+=1;
        sum+=tmp;
        if(sum>=20){
            ans++;
            tmp=sum=0;
        }
    }
    if(sum) ans++;
    printf("%d\n",ans);
    return 0;
}
View Code

 

D.Delivery Delays

 


E.Delivery Delays

    首先我們可以發現,因為每個士兵的血量最大為6,且敵我雙方的士兵數均為5,因此我們考慮可以用搜索的方法去解決。

    因為士兵的總血量的狀態比較少,因此我們可以考慮用一個12位的long long的每一位去儲存每一種血量的個數。此時,這每一個12位的long long整型就唯一代表了一種狀態。而又因為在搜尋的過程中,每一種曾經訪問過的狀態所對應的概率必定是唯一的,因此我們只需要用記憶化的形式對曾經出現過的結果記進行記錄,以達到剪枝的作用。

    因為我們要記錄的是敵軍死亡的概率,因此,我們可以優先將敵軍的6種血量置於12位long long的高位,這樣,當我們訪問到的狀態值<1000000,則代表已經敵軍已經已經死亡,即可直接跳出遞迴(又一個剪枝)。

    最後只需要將相應的概率相乘並相加即為答案。

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
int mp[2][10];
unordered_map<ll,double>dp;//充當記憶化陣列
ll GetSta(){//獲取狀態
    ll res=0;
    for(int i=1;i<=6;i++) res*=10,res+=mp[1][i];
    for(int i=1;i<=6;i++) res*=10,res+=mp[0][i];
    return res;
}
double dfs(ll sta,int limit){
    if(dp.count(sta)) return dp[sta];//如果該狀態曾經訪問過,則直接呼叫結果
    if(sta<1000000) return 1;//如果該狀態的值<1000000,則證明敵人已死,返回1
    if(limit==0) return 0;
    int cnt=0;
    for(int i=0;i<2;i++)//獲取總人數
        for(int j=1;j<=6;j++) cnt+=mp[i][j];
    double res=0;
    for(int i=0;i<2;i++){
        for(int j=1;j<=6;j++){
            if(!mp[i][j]) continue;
            mp[i][j]--;
            mp[i][j-1]++;
            ll newsta=GetSta();
            double tmp=dfs(newsta,limit-1);//dfs求解下一層的答案
            dp[newsta]=tmp;
 
            mp[i][j]++;//回溯
            mp[i][j-1]--;
 
            res+=1.0*mp[i][j]/cnt*tmp;//統計概率
        }
    }
    return res;
}
int main()
{
    int n,m,d,num;
    scanf("%d%d%d",&n,&m,&d);
    for(int i=0;i<n;i++){
        scanf("%d",&num);
        mp[0][num]++;
    }
    for(int i=0;i<m;i++){
        scanf("%d",&num);
        mp[1][num]++;
    }
    double res=dfs(GetSta(),d);
    printf("%.8f\n",res);
}
View Code

F.Firing the Phaser


G.Game Scheduling


H.House Lawn

    為了保證對於任意的T而言,T週一定能夠完成T項任務,因此我們只需要對每一件商品列舉週期T(0<=T<=間隔+工作時間),判斷是否能在某個整週期完成至少一次工作即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
double eps=1e-8;
int sgn(double x){
    if(fabs(x)<eps) return 0;
    if(x<eps) return -1;
    else return 1;
}
int n,m;
struct data{
    string s;
    int p,c,t,r;
    int id;
    bool operator < (const data& x)const{
        if(p==x.p) return id>x.id;
        return p>x.p;
    }
}d[maxn];
int main(){
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    scanf("%d%d",&n,&m);
    priority_queue<data>q;
    for(int i=1;i<=m;i++){
        getchar();
        char ch=getchar();
        while(ch!=','){d[i].s+=ch;ch=getchar();}
        scanf("%d,%d,%d,%d",&d[i].p,&d[i].c,&d[i].t,&d[i].r);
        d[i].id=i;
    }
    for(int i=1;i<=m;i++){
        bool flag=0;
        for(int T=1;T<=d[i].t+d[i].r;T++){
            if(flag) break;
            long long sum1=10080*T;
            long long sum=0;
            long long tmp=sum1/(d[i].r+d[i].t);
            tmp*=d[i].t;
            long long tmp1=sum1%(d[i].r+d[i].t);
            tmp1=min(tmp1,1LL*d[i].t);
            sum+=(tmp+tmp1)*d[i].c;
            if(sum<1LL*n*T) flag=1;
        }
        if(!flag) q.push(d[i]);
    }
    if(q.empty()){puts("no such mower");return 0;}
    data u=q.top();
    q.pop();
    cout<<u.s<<endl;
    while(!q.empty()&&u.p==q.top().p){
        cout<<q.top().s<<endl;
        q.pop();
    }
    return 0;
}
View Code

I.Intergalactic Bidding

題解待更

import java.math.*;
import java.util.*;
import java.io.*;
import java.lang.reflect.Array;
public class Main {
    public static void main(String[] args) {
        
        class A implements Comparable<A>{
            String name;
            BigInteger num;
            public int compareTo(A rhs) {
                return num.compareTo(rhs.num);
            }
        }
        A[] a=new A[1005];
        int[]ans =new int[1005];
        Scanner sca=new Scanner(System.in);
        int n=sca.nextInt();
        BigInteger s=sca.nextBigInteger();
        for(int i=1;i<=n;i++) {
            a[i]=new A();
            a[i].name=sca.next();
            a[i].num=sca.nextBigInteger();
        }
        Arrays.sort(a,1,n+1);
        int ansz=0;
        for(int i=n;i>=1;i--) {
            if(a[i].num.compareTo(s)<=0) {
                ans[ansz++]=i;
                s=s.subtract(a[i].num);
            }
        }
        if(ansz==0||s.compareTo(BigInteger.ZERO)!=0) {
            System.out.println(0);
        }
        else {
            System.out.println(ansz);
            for(int i=0;i<ansz;i++) {
                System.out.println(a[ans[i]].name);
            }
        }
    }
}
View Code

J.Jumbled String

題解待更

#include<bits/stdc++.h>
using namespace std;
bool check(long long x,long long ans){
    if(x*(x-1)/2<=ans) return 1;
    return 0;
}
int main(){
  //  freopen("in.txt","r",stdin);
 //   freopen("out.txt","w",stdout);
    long long  a,b,c,d;
    scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
    if (a==0&&b==0&&c==0&&d==0) {
        printf("0\n");
        return 0;
    }
    long long l=1,r=1e9;
    long long ans=0;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid,a)) {l=mid+1;ans=mid;}
        else r=mid-1;
    }
    long long ans1=0;
    l=1,r=1e9;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid,d)) {l=mid+1;ans1=mid;}
        else r=mid-1;
    }
  //  cout<<ans<<' '<<ans1<<endl;
    if (a==0&&b==0&&c==0&&d!=0){
        if (ans1*(ans1-1)/2==d) {
            for (int i=1;i<=ans1;i++) printf("1");
            printf("\n");
        }else printf("impossible\n");
        return 0;
    }
      if (a!=0&&b==0&&c==0&&d==0){
        if (ans*(ans-1)/2==a) {
            for (int i=1;i<=ans;i++) printf("0");
            printf("\n");
        }else printf("impossible\n");
        return 0;
    }


    if (ans1*ans!=b+c||ans*(ans-1)/2!=a||ans1*(ans1-1)/2!=d) printf("impossible\n");
    else{
        long long tmp=b%ans,tmp2=b/ans;
        if (tmp==0) {
            tmp=ans;
            for (int i=1;i<=ans1-tmp2;i++) printf("1");
            for(int i=1;i<=ans;i++) printf("0");
            for (int i=ans1-tmp2+1;i<=ans1;i++) printf("1");
            printf("\n");
        }else {
            for (int i=1;i<ans1-tmp2;i++) printf("1");
            for(int i=1;i<=tmp;i++) printf("0");
            printf("1");
            for (int i=tmp+1;i<=ans;i++) printf("0");
            for (int i=ans1-tmp2+1;i<=ans1;i++) printf("1");
            printf("\n");
        }
    }
    return 0;
}
View Code

K.King's Colors

題解待更

#include <iostream>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=2507;
ll inv[maxn],f[maxn],finv[maxn];
ll powm(ll x,ll n){
    ll res=1;
    while (n){
        if (n&1) res=res*x%mod;
        n>>=1;
        x=x*x%mod;
    }
    return res;
}
void init(){
    inv[1]=1;
    for (int i=2;i<maxn;i++)
        inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    f[0]=finv[0]=1;
    for (int i=1;i<maxn;i++){
        f[i]=f[i-1]*i%mod;
        finv[i]=finv[i-1]*inv[i]%mod;
    }
}
ll C(ll n,ll m){
    if (n<0||m<0||m>n) return 0;
    return f[n]*finv[m]%mod*finv[n-m]%mod;
}
int main(){
    init();
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,k;
    cin>>n>>k;
    ll ans=0;
    for (int i=0,f=1;i<k;i++,f=-f)
        ans=(ans+f*(k-i)%mod*powm(k-i-1,n-1)%mod*C(k,i)%mod+mod)%mod;
    cout<<ans<<endl;
    return 0;
}
View Code