2017/11/9模拟赛总结
来源:互联网 发布:axure7.0mac中文版下载 编辑:程序博客网 时间:2024/06/06 11:02
NOIP前最后一场模拟赛
T1 K值查询
二分答案
关键是如何check
解法1
假设当前二分答案的区间为
即求在
考虑枚举两数相乘中较小的那个数
在
而中间有一部分计算重复了 减去即可
#include<bits/stdc++.h>using namespace std;int n,m; long long check(int x){ int i,t=sqrt(x); long long sum=0; for (i=1;i<=min(t,n);i++) sum=sum+x/i; for (i=1;i<=min(t,m);i++) sum=sum+x/i; return sum-t*t;}int main(){ int q; scanf("%d%d%d",&n,&m,&q); while (q--){ int x; scanf("%d",&x); int l=1,r=x,res=0; while (l<=r){ int mid=(l+r)>>1; if (check(mid)>=x) res=mid,r=mid-1; else l=mid+1; } printf("%d\n",res); } return 0;}
解法2
其实
而
那么可以用简单的除法找到每个取值的区间 然后求和即可
#include<bits/stdc++.h>using namespace std;int n,m; long long check(int x){ int i,j; long long sum=0; for (i=m;i;i=j){ j=x/(x/i+1); sum+=x/i*(i-j); } return sum;}int main(){ int q; scanf("%d%d%d",&n,&m,&q); while (q--){ int x; scanf("%d",&x); int l=1,r=x,res=0; while (l<=r){ int mid=(l+r)>>1; if (check(mid)>=x) res=mid,r=mid-1; else l=mid+1; } printf("%d\n",res); } return 0;}
T2 成绩比较
看起来就像是dp+组合数 但是实现起来并不简单
前面的那个组合数是在剩下没有确定的人中选出
后面的那个组合数是把这门功课剩下比B高的位置分给前面的人(为什么不分给后面才确定的人?因为分给后面的人就会导致确定不被碾压的人更多 和dp状态不符)
人的方案解决了 还需要乘上每门科目所有人分数的方案数
可以枚举B的分数
但是
换一个思路 考虑枚举比B大的人 和小于等于B的人不同分数的个数(设为
那么贡献为
其中
也就是有序的第二类斯特林数 可以用
这样答案乘上所有方案数即可
#include<bits/stdc++.h>using namespace std;#define N 110#define mo 1000000007int n,m,K,u[N],r[N];int C[N][N],dp[N][N],S[N][N],c[N],Inv[N];int Pow(int A,int B){ int res=1; while (B){ if (B&1) res=1LL*res*A%mo; B>>=1; A=1LL*A*A%mo; } return res;}void init(){ int i,j; for (i=0;i<=n;i++){ C[i][0]=1; for (j=1;j<=i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mo; } S[0][0]=1; for (i=1;i<=n;i++) for (j=1;j<=i;j++) S[i][j]=1LL*(S[i-1][j-1]+S[i-1][j])*j%mo; for (i=1;i<=n;i++) Inv[i]=Pow(i,mo-2);}void solve(){ int i,j,k; init(); dp[0][0]=1; for (i=1;i<=m;i++) for (j=0;j<=n-K-1;j++) for (k=max(0,j-(r[i]-1));k<=j;k++) dp[i][j]=(dp[i][j]+1LL*dp[i-1][k]*C[n-1-k][j-k]%mo*C[k][r[i]-1-(j-k)]%mo)%mo; int sum=dp[m][n-K-1]; for (i=1;i<=m;i++){ int tmp=0; c[0]=1; for (j=1;j<=n;j++) c[j]=1LL*c[j-1]*(u[i]-j+1)%mo*Inv[j]%mo; for (j=0;j<r[i];j++) for (k=1;k<=n-r[i]+1;k++) tmp=(tmp+1LL*(S[n-r[i]][k]+S[n-r[i]][k-1])*S[r[i]-1][j]%mo*c[j+k])%mo; sum=1LL*sum*tmp%mo; } printf("%d\n",sum);}int main(){ int i; scanf("%d%d%d",&n,&m,&K); for (i=1;i<=m;i++) scanf("%d",&u[i]); for (i=1;i<=m;i++) scanf("%d",&r[i]); solve(); return 0;}
T3 数塔
只需要正反各推一遍 得到某个点向上/向下的最大路径
然后对于每一行累计一下前缀/后缀最大值 就可以
#include<bits/stdc++.h>using namespace std;#define N 1010#define M 500010int a[N][N],n,m,dp1[N][N],dp2[N][N],suml[N][N],sumr[N][N];int main(){ int i,j; scanf("%d%d",&n,&m); for (i=1;i<=n;i++) for (j=1;j<=i;j++) scanf("%d",&a[i][j]); dp1[1][1]=a[1][1]; for (i=2;i<=n;i++) for (j=1;j<=i;j++) dp1[i][j]=max(dp1[i-1][j-1],dp1[i-1][j])+a[i][j]; for (i=1;i<=n;i++) dp2[n][i]=a[n][i]; for (i=n-1;i>=1;i--) for (j=1;j<=i;j++) dp2[i][j]=max(dp2[i+1][j+1],dp2[i+1][j])+a[i][j]; for (i=1;i<=n;i++){ for (j=1;j<=i;j++) suml[i][j]=max(suml[i][j-1],dp1[i][j]+dp2[i][j]-a[i][j]); for (j=i;j>=1;j--) sumr[i][j]=max(sumr[i][j+1],dp1[i][j]+dp2[i][j]-a[i][j]); } for (i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); if (x==1 && y==1){ printf("-1\n"); continue; } printf("%d\n",max(suml[x][y-1],sumr[x][y+1])); } return 0;}
NOIP2017倒计时2天
如果遇到第二题很难的话应该及时跳过 而不是死磕
做题策略还是很重要的
Date:2017/11/9
By CalvinJin
- 2017/11/9模拟赛总结
- 2017/10/9模拟赛总结
- 2017/11/3模拟赛总结
- 2017/11/4模拟赛总结
- 2017/11/5模拟赛总结
- 2017/11/6模拟赛总结
- 2017/11/7模拟赛总结
- 2017/11/8模拟赛总结
- 9-11NOIP模拟赛总结
- 2015.12.9模拟赛总结
- NOIP2017模拟赛(9) 总结
- NOIP2017模拟赛(11) 总结
- 9-9NOIP模拟赛总结
- 2017/10/7模拟赛总结
- 2017/10/10模拟赛总结
- 2017/10/6模拟赛总结
- 2017/10/12模拟赛总结
- 2017/10/15模拟赛总结
- opencv 手写选择题阅卷 (一)表格设计与识别
- Maven 运行错误GC overhead limit exceeded解决方法
- HDU 6223 Infinite Fraction Path
- codeforces 120E Put Knight!
- 【WEB】HTML标签自带属性title样式修改
- 2017/11/9模拟赛总结
- 习题6.2
- Honeywell WinCE6.0 开发包(D6X10 Device SDK for WinCE 6.0)
- springmvc的拦截器使用
- @EXPORT 和@EXPORT_OK区别
- phoenix secondary
- oj第四周作业题解
- 十六进制查看搜索
- poj2507 Crossed ladders