@sensitive-cs
2017-04-27T07:05:14.000000Z
字数 3615
阅读 981
题解
补题第一题 切pizza:
思路:
赛上没有想到二分,用了线段树,可惜代码没有跑出来,当然,线段树其实是行不通的,因为是面积,除非二维线段树(2333,不知道有没有。后来,wj菊苣讲题解的时候说二分,因为美味度是随坐标单调增加的唉,然后又就没有听啦,当时太饿了。
然后,自己写的二分wa了十几遍过不了,很悲伤,是脑子除了问题,所以问了好人mz学长。
此题暴露出来的问题有:
1.二分判浮点精度的时候不能自己手写精度,一般这种要求精度的题用循环就可以了。
2.very important,m和n的范围是在1e5的范围内,所以相乘的话有可能会爆int,就是没想到,所以n*m的时候就直接乘在了1.0前面,后面读题时,第一是一定能要预判所有数据的最大范围,第二就是直接用long long或者double之类的就好了。mark一下,仔细一点。
代码:
#include <stdio.h>#include <string.h>#include <math.h>const double pi = acos(-1.0);struct node{double cen;double deg;double r;}node[100005];int n,m,k;double mm(double g){double sum = 0;for (int i = 0;i < k;i++){if (node[i].cen + node[i].r <= g){sum += pi * node[i].r * node[i].r * node[i].deg;}else if (node[i].cen < g && node[i].cen + node[i].r > g){double x = g - node[i].cen;double w = 2 * (acos(x / node[i].r));double area = pi * node[i].r * node[i].r - (1.0 / 2 * w * node[i].r * node[i].r - 1.0 / 2 * node[i].r * node[i].r * sin(w));sum += area * node[i].deg;}else if (node[i].cen - node[i].r < g && node[i].cen > g){double x = node[i].cen - g;double w = 2 * (acos(x / node[i].r));double area = 1.0 / 2 * w * node[i].r * node[i].r - 1.0 / 2 * node[i].r * node[i].r * sin(w);sum += area * node[i].deg;}else if (node[i].cen == g)sum += 1.0 / 2 * pi * node[i].r * node[i].r;}return sum + m * g;}int main(){int t;scanf("%d",&t);while (t--){double sum = 0;scanf("%d%d%d",&n,&m,&k);for (int i = 0;i < k;i++){double t1;scanf("%lf%lf%lf%lf",&node[i].cen,&t1,&node[i].r,&node[i].deg);sum += pi * node[i].r * node[i].r * node[i].deg;}sum += 1.0 * n * m;double l = 0,h = n,mid;for (int i = 0;i < 100;i++){mid = (l + h) / 2;if (mm(mid) >= sum / 2) h = mid;else l = mid;//printf("%f*****\n",mid);}printf("%.4f\n",mid);}return 0;}
补题第二题 24game:
这题在赛上写爆搜,兰儿wa了二十几发。赛下来写,我不是用的dfs。
第一种想法是枚举所有数字与符号的全排列,但是后来经过mzjj的验证有些情况是过不了的,并不能涵盖所有括号的情况,遂重新写。
后来去网上查了资料,发现了后缀表达式与表达式树,经过两节高数了的深思熟虑(滑稽,想出来了全排列与表达式树相结合的方法,1A了。
表达式树有三种:
1.(x op y)op(z op w);
2.(x op y) op z op w
3.x op y op (z op w)
主要是从 8 8 3 3这个想出来的
代码:
#include <stdio.h>#include <math.h>#include <string.h>int a[4];bool v[4];int p[4];char b[1000][3];int cnt = 0;bool flag = 0;double cal(double x,int op,double y){double ans;if (op == 0)ans = x + y;if (op == 1)ans = x - y;if (op == 2)ans = x * y;if (op == 3){if (y == 0)ans = 100000000000;elseans = x / y;}return ans;}void dfs(void){double c[4];for (int i = 0;i < 4;i++)c[i] = a[p[i]];for (int i = 0;i < cnt;i++){if (flag) break;double ans;double x = cal(c[0],b[i][0],c[1]);double y = cal(c[2],b[i][2],c[3]);ans = cal(x,b[i][1],y);if (fabs(ans - 24) < 1e-8)flag = 1;ans = cal(c[0],b[i][0],c[1]);ans = cal(ans,b[i][1],c[2]);ans = cal(ans,b[i][2],c[3]);if (fabs(ans - 24) < 1e-8)flag = 1;ans = cal(c[0],b[i][0],c[1]);ans = cal(c[2],b[i][1],ans);ans = cal(c[3],b[i][2],ans);if (fabs(ans - 24) < 1e-8)flag = 1;}}void fun(int k){if (flag) return;if (k == 4)dfs();for (int i = 0;i < 4;i++){if (!v[i]){v[i] = 1;p[k] = i;fun(k+1);v[i] = 0;}}}int main(){int t;scanf("%d",&t);for (int i = 0;i < 4;i++)for (int j = 0;j < 4;j++)for (int k = 0;k < 4;k++){b[cnt][0] = i;b[cnt][1] = j;b[cnt][2] = k;cnt++;}while (t--){flag = 0;memset(v,0,sizeof(v));memset(p,0,sizeof(p));for (int i = 0;i < 4;i++)scanf("%d",&a[i]);fun(0);if (flag)printf("Yes\n");elseprintf("No\n");}return 0;}
第三题 马(无敌js
思路:首先可以推出马可以到达的坐标,横纵坐标之和必须是3的倍数,其次,此坐标必须满足杨辉三角,即abs(n-m) <= (n + m) / 3。之后,就是大组合数取模的问题了。
求解这个问题,主要用到了几个定理。
第一,Lucas定理:
mark 一下
第二 费马小定理:
a的逆元就是a的p-2次方
第三:
依据费马小定理,计算逆元时需要用到快速幂算法。
这题主要是学习新姿势。
代码:
#include <stdio.h>typedef long long ll;const ll p = 1000003;int abs(int x){if (x < 0)return -x;elsereturn x;}ll quick_mod(ll a,ll b){if (b == 0) return 1;ll x = quick_mod(a,b / 2);ll ans = x * x % p;if (b % 2) ans = ans * a % p;return ans;}ll C(ll n, ll m){if (m > n) return 0;ll ans = 1;for (int i = 1;i <= m;i++){ll a = n - m + i;ll b = i;ans = ans * (a * quick_mod(b,(p - 2)) % p) % p;}return ans;}ll Lucas(ll n,ll m){if (m == 0)return 1;elsereturn C(n % p,m % p) * Lucas(n / p,m / p) % p;}int main(){int t;scanf("%d",&t);while (t--){int n,m;scanf("%d%d",&n,&m);n--;m--;if ((m + n) % 3 == 0){if (abs(n-m) > (n + m) / 3)printf("0\n");elseprintf("%lld\n",Lucas((n + m) / 3,m - (n + m) / 3));}elseprintf("0\n");}return 0;}