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("View Code%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); }
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