百度之星2020 初赛三场 部分题解
初赛一:
1001 Drink:$\max\left\{\left\lceil\frac{m}{x}\right\rceil\cdot y\right\}$
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i, l, r) for (int i = (l); i <= (r); i++) 4 using namespace std; 5 6 int T, n, m, x, y; 7 8 int main(){ 9 freopen("drink.in", "r", stdin); 10 freopen("drink.out", "w", stdout); 11 for (scanf("%d", &T); T--; ) { 12 scanf("%d%d", &n, &m); int ans = 1e8; 13 rep(i, 1, n) scanf("%d%d", &x, &y), ans = min(ans, ((m - 1) / x + 1) * y); 14 printf("%d\n", ans); 15 } 16 return 0; 17 }
1002 GPA:模拟DP。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i, l, r) for (int i = (l); i <= (r); i++) 4 using namespace std; 5 6 int T, n; 7 double f[500]; 8 9 double G(int x) { 10 if (x >= 95) return 4.3; 11 if (x >= 90) return 4.0; 12 if (x >= 85) return 3.7; 13 if (x >= 80) return 3.3; 14 if (x >= 75) return 3.0; 15 if (x >= 70) return 2.7; 16 if (x >= 67) return 2.3; 17 if (x >= 65) return 2.0; 18 if (x >= 62) return 1.7; 19 if (x >= 60) return 1.0; 20 return 0; 21 } 22 23 int main(){ 24 freopen("GPA.in", "r", stdin); 25 freopen("GPA.out", "w", stdout); 26 f[0]=0; 27 rep(i, 1, 400) rep(j, 1, min(i, 100)) 28 f[i] = max(f[i], f[i - j] + G(j)); 29 for (scanf("%d", &T); T--; ) 30 scanf("%d", &n),printf("%.1lf\n", f[n]); 31 return 0; 32 }
1003 Dec:先打表。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 using namespace std; 5 6 const int N=1050; 7 int T,x,y,mp[N][N]; 8 9 int main(){ 10 freopen("dec.in","r",stdin); 11 freopen("dec.out","w",stdout); 12 mp[1][1]=1; 13 rep(i,2,1000) rep(j,1,i) 14 mp[i][j]=(__gcd(i,j)==1)+max(mp[i-1][j],mp[i][j-1]); 15 for (scanf("%d",&T); T--; ) 16 scanf("%d%d",&x,&y),printf("%d\n",mp[max(x,y)][min(x,y)]); 17 return 0; 18 }
1004 Civilization:枚举建立城市的位置,统计附近(曼哈顿距离3以内)各a值的点各有多少个,按a从高到低一次放居民,模拟即可。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 using namespace std; 5 6 const int N=510; 7 int T,n,x0,y0,ans,f[4],a[N][N]; 8 9 int main(){ 10 freopen("1004.in","r",stdin); 11 freopen("1004.out","w",stdout); 12 for (scanf("%d",&T); T--; ){ 13 scanf("%d%d%d",&n,&x0,&y0); ans=1e8; 14 rep(i,1,n) rep(j,1,n) scanf("%d",&a[i][j]); 15 rep(x,1,n) rep(y,1,n){ 16 int sm=(abs(x-x0)+abs(y-y0)+1)/2,tot=0; 17 rep(i,x-3,x+3) rep(j,y-3,y+3) 18 if (i>=1 && i<=n && j>=1 && j<=n && abs(i-x)+abs(j-y)<=3) f[a[i][j]]++; 19 int s=a[x][y]; f[s]--; 20 rep(k,1,8){ 21 int t=(8*k*k-tot-1)/s+1; sm+=t; tot+=t*s; 22 if (f[3]) s+=3,f[3]--; 23 else if (f[2]) s+=2,f[2]--; 24 else if (f[1]) s+=1,f[1]--; 25 } 26 ans=min(ans,sm); 27 } 28 printf("%d\n",ans); 29 } 30 return 0; 31 }
1005 内层块长必定比外层短,故内层的一块至多与外层的一块相连,而外层则不一定,故若将每个黑块看成一个点,相邻两层的相连黑块之间连边,则构成一个森林。森林的连通块数=点数-边数。点数显然,考虑边数期望。
考虑外层的一个黑块,与内层某黑块相连的概率为$\frac{\frac{2\pi}{a_{i-1}}+\frac{2\pi}{a_{i}}}{2\pi}=\frac{1}{a_{i-1}}+\frac{1}{a_{i}}$,故相邻两层边数期望为$(\frac{1}{a_{i-1}}+\frac{1}{a_{i}})\cdot\frac{a_i}{2}\cdot\frac{a_{i-1}}{2}=\frac{a_i+a_{i-1}}{4}$。
最后答案化简为$\frac{a_1+a_n}{4}$
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 typedef long long ll; 5 using namespace std; 6 7 const int N=1010,mod=1e9+7; 8 int T,n,a[N]; 9 10 int ksm(int a,int b){ 11 int res=1; 12 for (; b; a=1ll*a*a%mod,b>>=1) 13 if (b & 1) res=1ll*res*a%mod; 14 return res; 15 } 16 17 int main(){ 18 freopen("rotate.in","r",stdin); 19 freopen("rotate.out","w",stdout); 20 for (scanf("%d",&T); T--; ){ 21 scanf("%d",&n); 22 rep(i,1,n) scanf("%d",&a[i]); 23 printf("%lld\n",1ll*(a[1]+a[n])*ksm(4,mod-2)%mod); 24 } 25 return 0; 26 }
初赛二:
1001 Poker:直接模拟,发现迷之错误时多换几次实数运算的写法。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 using namespace std; 5 6 int T,n,m,p; 7 8 int main(){ 9 for (scanf("%d",&T); T--; ){ 10 scanf("%d%d%d",&n,&m,&p); 11 int t=m-(int)(m*(100-p)/100.); 12 printf("%d\n",(n<m)?0:((n-m)/t+1)); 13 } 14 return 0; 15 }
1002 Distance:所有点必然排在一条直线上否则没法做,于是必然都在P0同侧。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 typedef long long ll; 5 using namespace std; 6 7 const int N=100010; 8 int T,n,a[N]; 9 ll ans,sm[N]; 10 11 int main(){ 12 for (scanf("%d",&T); T--; ){ 13 scanf("%d",&n); 14 rep(i,1,n) scanf("%d",&a[i]); 15 sort(a+1,a+n+1); sm[0]=ans=0; 16 rep(i,1,n) sm[i]=sm[i-1]+a[i]; 17 rep(i,1,n-1) ans+=sm[n]-sm[i]-1ll*(n-i)*a[i]; 18 printf("%lld\n",ans); 19 } 20 return 0; 21 }
1003 Covid:把各事件写成<时间,地点,人>三元组用map存储,然后按时间顺序将同一时间同一地点的所有时间放在一起处理即可,线性。
1 #include<cstdio> 2 #include<vector> 3 #include<algorithm> 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 5 using namespace std; 6 7 const int N=20010; 8 int T,n,m,s[N],b[N]; 9 vector<int>mp[110][11]; 10 11 int main(){ 12 for (scanf("%d",&T); T--; ){ 13 scanf("%d",&n); b[1]=1; 14 rep(i,2,n) b[i]=0; 15 rep(i,1,100) rep(j,1,10) mp[i][j].clear(); 16 rep(i,1,n){ 17 scanf("%d",&m); int t,p; 18 rep(j,1,m) scanf("%d%d",&t,&p),mp[t][p].push_back(i); 19 } 20 rep(i,1,100) rep(j,1,10){ 21 int s=mp[i][j].size(),flag=0; 22 rep(k,0,s-1) if (b[mp[i][j][k]]) flag=1; 23 if (flag) rep(k,0,s-1) b[mp[i][j][k]]=1; 24 } 25 int tot=0; rep(i,1,n) if (b[i]) s[++tot]=i; 26 rep(i,1,tot-1) printf("%d ",s[i]); printf("%d\n",s[tot]); 27 } 28 return 0; 29 }
1004 Car:可以DP,但bestcoder机子跑的比较快爆搜可过。DP做法设f[i][S]为前i天禁止尾号状态为S(压成二进制)的最优解,转移显然。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 using namespace std; 5 6 char str[10]; 7 int T,n,ans,s[20],d[20]; 8 9 void dfs(int x){ 10 if (x==10){ 11 int res=20000; 12 rep(i,1,5) res=min(res,d[i]); 13 ans=max(ans,res); 14 return; 15 } 16 rep(i,1,5) d[i]+=s[x],dfs(x+1),d[i]-=s[x]; 17 } 18 19 int main(){ 20 for (scanf("%d",&T); T--; ){ 21 scanf("%d",&n); ans=0; 22 rep(i,0,9) s[i]=d[i]=0; 23 rep(i,1,n) scanf("%s",str),s[str[4]-'0']++; 24 dfs(0); printf("%d\n",n-ans); 25 } 26 return 0; 27 }
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 5 using namespace std; 6 7 const int N=10010; 8 char s[10]; 9 int n,T,p[11],a[N],d[11][N]; 10 11 int main(){ 12 for (scanf("%d",&T); T--; ){ 13 scanf("%d",&n); 14 rep(i,0,9) p[i]=0; 15 rep(i,1,n) scanf("%s",s+1),a[i]=s[5]-'0',p[a[i]]++; 16 memset(d,0x3f,sizeof(d)); d[0][0]=0; 17 rep(i,1,5) rep(j,0,(1<<10)-1) for (int k=j; ; k=(k-1)&j){ 18 int t=j^k,sm=0; 19 rep(l,0,9) if (!((t>>l)&1)) sm+=p[l]; 20 d[i][j]=min(d[i][j],max(d[i-1][k],sm)); 21 if (!k) break; 22 } 23 printf("%d\n",d[5][(1<<10)-1]); 24 } 25 return 0; 26 }
初赛三:
1001 Discount:模拟。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 using namespace std; 5 6 int T,n,b; 7 double c,ans; 8 9 int main(){ 10 for (scanf("%d",&T); T--; ){ 11 scanf("%d",&n); ans=-1; 12 rep(i,1,n) scanf("%d%lf",&b,&c),ans=max(ans,(1-c)/(b+1-c)); 13 printf("%.5lf\n",ans); 14 } 15 return 0; 16 }
1002 Game:p>1则显然p=2x,否则(x/2+x*2)/2=1.25x>x,则换一定更优。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 using namespace std; 5 6 int T; 7 double p; 8 9 int main(){ 10 for (scanf("%d",&T); T--; ) 11 scanf("%lf",&p),puts((p>1)?"No":"Yes"); 12 return 0; 13 }
1003 Permutation:要想逆序对尽量多,就<1,n>,<2,n-1>,...分别依次交换即可。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 using namespace std; 5 6 int T,n,m; 7 8 int main(){ 9 for (scanf("%d",&T); T--; ) 10 scanf("%d%d",&n,&m),m=min(m,n/2),printf("%lld\n",(n==1)?0ll:1ll*(2*n-3)*m-2ll*m*(m-1)); 11 return 0; 12 }
1004 Intersection:只考虑两列最后一辆车,左侧设为A,右侧为B。若A>B则B不挡A,答案就是A的步数。若A<=B-2则B必然比A后到达,答案为B的步数。A=B或A=B-1时答案为B的步数+1。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 using namespace std; 5 6 int T,n,s1,s2,x,y; 7 8 int main(){ 9 for (scanf("%d",&T); T--; ){ 10 scanf("%d",&n); s1=s2=0; 11 rep(i,1,n){ 12 scanf("%d%d",&x,&y); 13 if (x==1) s2=max(s2,y); else s1=max(s1,y); 14 } 15 if (s1 && (s1==s2-1 || s1==s2)) printf("%d\n",s2+2); 16 if ((!s1) || s1<=s2-2) printf("%d\n",s2+1); 17 if (s1>s2) printf("%d\n",s1+2); 18 } 19 return 0; 20 }
1005 Chess:f[i][j]表示1~i中放了j个传送器,且保证1能到i的方案数。枚举上一个没放传送器的位置,两地之间的位置的传送器传送到哪没有限制。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 5 typedef long long ll; 6 using namespace std; 7 8 const int N=1010,mod=1e9+7; 9 int T,n,m,f[N][N]; 10 11 int main(){ 12 for (scanf("%d",&T); T--; ){ 13 scanf("%d%d",&n,&m); memset(f,0,sizeof(f)); f[1][0]=1; 14 rep(i,1,n) rep(j,0,min(m,i-1)){ 15 int t=1; 16 rep(k,1,11) f[i+k][j+k-1]=(f[i+k][j+k-1]+1ll*f[i][j]*t)%mod,t=1ll*t*(i+k-1)%mod; 17 } 18 printf("%lld\n",f[n][m]?f[n][m]:-1ll); 19 } 20 return 0; 21 }
1006 Ant:https://blog.csdn.net/tomjobs/article/details/107684591
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 #define For(i,x) for (int i=h[x],k; i; i=nxt[i]) 5 typedef long long ll; 6 using namespace std; 7 8 const int N=200010,mod=1e9+7; 9 int T,n,m,cnt,x,y,h[N],to[N],nxt[N],f1[N],f2[N],sz[N]; 10 11 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } 12 13 int ksm(int a,int b){ 14 int res=1; 15 for (; b; a=1ll*a*a%mod,b>>=1) 16 if (b & 1) res=1ll*res*a%mod; 17 return res; 18 } 19 20 void dfs(int x,int fa){ 21 if (x==m){ f1[x]=1; return; } 22 For(i,x) if ((k=to[i])!=fa){ 23 dfs(k,x); 24 if (f1[k]){ 25 f1[x]=1ll*f1[k]*ksm(sz[x],mod-2)%mod; 26 f2[x]=1ll*f2[k]*ksm(sz[x],mod-2)%mod; 27 f2[x]=(f2[x]+1ll*f1[x]*ksm(sz[x]-1,mod-2)%mod*(sz[x]-1-(x!=1)))%mod; 28 } 29 } 30 } 31 32 int main(){ 33 for (scanf("%d",&T); T--; ){ 34 scanf("%d%d",&n,&m); cnt=0; 35 rep(i,1,n) h[i]=f1[i]=f2[i]=sz[i]=0; 36 rep(i,2,n) scanf("%d%d",&x,&y),add(x,y),add(y,x),sz[x]++,sz[y]++; 37 dfs(1,0); printf("%d\n",(f1[1]+f2[1])%mod); 38 } 39 return 0; 40 }