Gym 101775 2017-2018 ACM-ICPC Asia East Continent League Final (ECL-Final 2017)
A.Chat Group
不難發現,題目中讓我們求的式子為:
而很顯然,因為n相當的大,因此直接做的話絕對會超時,因此考慮將式子轉化。
根據組合數的公式,上述的式子可以轉化為:
因為此時的k比較小,因此我們利用組合數公式遞推求解。
#include <bits/stdc++.h> #define maxn 100005 using namespace std; typedef long long ll; ll inv[maxnView Code+20]; const int mod=1e9+7; void init(){ inv[1]=inv[0]=1; for(int i=2;i<=maxn;i++){ inv[i]=(mod-mod/i)*inv[mod%i]%mod; } } ll powmod(ll a,ll b){ ll res=1; while(b){ if(b&1) res=res*a%mod; b>>=1; a=a*a%mod; } return res; } int main() { init();int t,n,k,cnt=0; scanf("%d",&t); while (t--){ scanf("%d %d",&n,&k); ll res=1,y=n,sum=1; for (int i=1;i<k;i++){ res=res*y%mod*inv[i]%mod; y--; sum=(res+sum)%mod; } ll ans=(powmod(2,n)-sum+mod)%mod; printf("Case #%d: %lld\n",++cnt,ans); } return 0; }
B.Scapegoat
首先必定是每一口鍋都讓一個替罪羊去背,因為要使得最後的方差最小,因此我們考慮根據值離總平均值的距離做判斷。
因此,我們必定是要讓每一口鍋平均分配出來的值儘可能的接近總的平均值。為此,我們需要對每一口鍋分別記錄,Var1=(嚴重值-平均值)^2 以及 Var2=(加了1個人分鍋後的嚴重值-平均值)^2。而要使得在整體上答案更優,我們必定是首先選取 Var1-Var2比較大的(證明選取它能夠使得該鍋的值更接近總的平均值)。因此我們只需要用一個優先佇列進行維護,每次不斷取隊頂的鍋,將一個人分配到那口鍋即可。
#include <bits/stdc++.h> #define maxn 200005 using namespace std; double ave; struct Node{ double all,var1,var2,cur;//Var1和Var2分別代表原來的值離平均值的距離以及(Var1-加上1個人分攤後的值離平均值的距離) int num; bool operator <(const Node &b)const{//在優先佇列中維護Var2即可 return var2<b.var2; } Node(double _all,int _num,double _cur){ all=_all,num=_num,cur=_cur; var1=(cur-ave)*(cur-ave)*num; var2=var1-(all/(num+1)-ave)*(all/(num+1)-ave)*(num+1); } }; priority_queue<Node>que; int a[maxn]; int main() { int t; scanf("%d",&t); int Case=0; while(t--){ int n,m,M; scanf("%d%d",&n,&m); M=m; double sum=0; for(int i=0;i<n;i++){ scanf("%d",&a[i]); sum+=a[i]; } ave=sum/m;//計算平均值 for(int i=0;i<n;i++){ Node now=Node(a[i],1,a[i]); que.push(Node(a[i],1,a[i])); } m-=n; while(m--){ Node now=que.top(); que.pop(); que.push(Node(now.all,now.num+1,now.all/(now.num+1))); } double res=0; for(int i=0;i<n;i++){//計算方差 res+=(que.top().cur-ave)*(que.top().cur-ave)*que.top().num; que.pop(); } res/=M; printf("Case #%d: %.8f\n",++Case,res); } }View Code
C.Traffic Light
#include<bits/stdc++.h> using namespace std; const int maxn=1007; int main(){ int t,cnt=0,n; scanf("%d",&t); while (t--){ scanf("%d",&n); double x,y,sum=0,mx=0; for (int i=0;i<=n;i++) { scanf("%lf",&x); sum+=x; } for (int i=1;i<=n;i++){ scanf("%lf%lf",&x,&y); mx=max(y,mx); } sum+=mx; printf("Case #%d: %.8f\n",++cnt,sum); } return 0; }View Code
D.Mr. Panda and Geometric Sequence
#include <bits/stdc++.h> using namespace std; typedef long long ll; vector<ll>vec; ll Pow[20]; int Count(ll n){ int cnt=0; while(n){ n/=10; cnt++; } return cnt; } void init(){ int n=1e5; Pow[0]=1; for(int i=1;i<=16;i++) Pow[i]=Pow[i-1]*10; for(int p=1;p<=n;p++){ for(int q=p+1;q<=n/p;q++){ if(__gcd(p,q)>1) continue; for(int k=1;k<=n/p/q;k++){ ll x=1ll*k*p*p,y=1ll*k*p*q,z=1ll*k*q*q; ll numx=Count(x),numy=Count(y),numz=Count(z); ll numall=numx+numy+numz; if(numall>15) break; ll now=z,res=x*Pow[numy+numz]+y*Pow[numz]+z; vec.push_back(res); while(1){ if(now%p!=0) break; now=now*q/p; if(numall+Count(now)>15) break; numall+=Count(now); res=res*Pow[Count(now)]+now; vec.push_back(res); } } } } sort(vec.begin(),vec.end()); vec.resize(unique(vec.begin(),vec.end())-vec.begin()); } ll Sum(ll n){ return upper_bound(vec.begin(),vec.end(),n)-vec.begin(); } int main() { int t; init(); scanf("%d",&t); int Case=0; while(t--){ ll l,r; scanf("%lld%lld",&l,&r); printf("Case #%d: %lld\n",++Case,Sum(r)-Sum(l-1)); } return 0; }View Code
E.Snakebird
F.Good Number
G.Image Recognition
H.Mr. Panda and Birthday Song
I.PLAYERUNKNOWN'S BATTLEGROUNDS
J.Straight Master
可以發現3,4,5可以湊出任意的3以上的數,還可以發現這個數列一直到第(n+1)位必然是升降相對應的,所以直接維護一個差分,相隔三以上的就可以正的負的相互懟掉,判斷最後所剩的是否是0就可以了
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+5; int T,n; int a[maxn],b[maxn]; void read(int &ret){ ret=0; char ch=getchar(); while(ch>'9'||ch<'0') ch=getchar(); while(ch>='0'&&ch<='9'){ ret=ret*10+ch-'0'; ch=getchar(); } } int cas; int main(){ read(T); while(T--){ read(n); for(int i=1;i<=n;i++) {read(a[i]);b[i]=a[i]-a[i-1];} b[n+1]=-a[n]; bool flag=0; if(b[2]<0||b[3]<0){printf("Case #%d: No\n",++cas);continue;} long long sum=0; for(int i=1;i<=n+1;i++){ if(b[i]>0) sum+=b[i]; int nxt=i+3; if(nxt>n+1) break; else if(b[nxt]<0) sum+=b[nxt]; if(sum<0){flag=1;break;} } if(flag||sum) printf("Case #%d: No\n",++cas); else printf("Case #%d: Yes\n",++cas); } return 0; }View Code
K.Downgrade
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=100005; int val[maxn]; long long sum[maxn]; int main(){ int T,cas=0; scanf("%d",&T); while(T--){ ll A,B,n; scanf("%lld%lld%lld",&A,&B,&n); for(int i=1;i<=A;i++){scanf("%d",&val[i]);sum[i]=sum[i-1]+val[i];} int m=A; while((n--)){ int tmp1,tmp2; tmp1=lower_bound(sum+1,sum+m+1,A)-sum; tmp2=A-sum[tmp1-1]; if(tmp1==A) { B=tmp2; break; } A=tmp1,B=tmp2; } printf("Case #%d: %lld-%lld\n",++cas,A,B); } return 0; }View Code
L.SOS
一步一步分析必勝態.
分析以下4個情況
n=4
n=7
n=8
n=15
很明顯必勝態是n=7
n=15的時候是可以調整為必勝態的
所以最後就可以發現
n<=6必定平手
7<=n<=15 不是平手就是先手必勝
15<n 分析出奇數時先手必勝,偶數時後手必勝
#include <bits/stdc++.h> #define maxn 100005 using namespace std; int main() { int T,n; scanf("%d",&T); for(int cas=1;cas<=T;cas++){ scanf("%d",&n); if(n<=6)printf("Case #%d: Draw\n",cas); else if((n&1))printf("Case #%d: Panda\n",cas); else if (n>=16) printf("Case #%d: Sheep\n",cas); else printf("Case #%d: Draw\n",cas); } return 0; }View Code
M.World Cup
溫暖的簽到題,只需要知道小組賽時有48場比賽,16強有8場比賽,8強有4場比賽,半決賽有2場比賽,決賽有1場比賽即可。
最後模擬一下就OK了。
#include<bits/stdc++.h> using namespace std; int di[5]={1,49,57,61,63}; int val[5]; int main(){ int T; long long ans; scanf("%d",&T); int cas=0; while(T--){ for(int i=0;i<5;i++) scanf("%d",&val[i]); ans=0; int n; scanf("%d",&n); for(int i=1;i<=n;i++){ int id; scanf("%d",&id); for(int j=4;j>=0;j--){ if(id>=di[j]){ ans+=val[j]; break; } } } ans*=10000; printf("Case #%d: %lld\n",++cas,ans); } return 0; }View Code