2014 牡丹江题解 (未完)

来源:互联网 发布:淘宝网购物如何退货 编辑:程序博客网 时间:2024/04/29 09:12

A:Average Score

水题不解释。

#include <cstdio>#include <cstring>#include <cassert>#include <queue>#include <cmath>#include <set>#include <algorithm>using namespace std;#define rep(i,a,b) for(int i=(a);i<(int)(b);++i)#define rrep(i,b,a) for(int i=(b);i>=(int)(a);--i)#define clr(a,x) memset(a,x,sizeof(a))#define eps 1e-8#define LL long long#define zero(x) (-eps < (x) && (x) < eps)#pragma comment(linker,"/STACK:102400000,102400000")int main(){    #ifdef ACM        freopen("in.txt","r",stdin);    #endif // ACM    int T; cin >> T;    while (T--) {        int n,m;        scanf("%d%d",&n,&m);        --n;        int sum = 0;        rep(i,0,n) {            int x; scanf("%d",&x);            sum += x;        }        double A = (double)sum/ n;        sum = 0;        rep(i,0,m) {            int x; scanf("%d",&x);            sum += x;        }        double B = (double) sum / m;        int r = floor(A-eps), l = ceil(B+eps);        printf("%d %d\n",l,r);    }}

B:Building Fire Stations

题意:给出一颗树,要在两个不同的点建立消防站,每个点会去离自己最近的消防站,问每个点距离自己最近的消防站的最短距离的最长距离是多少。


思路:可以二分一个答案K,然后判断K行不行。可以这样判断,在一棵有根树里面,我们考虑一下叶子,叶子是必须要被覆盖的,那么我们考虑深度最深的叶子,要覆盖这个点,我们可以选择把消防站建在这个叶子的第K个祖先处,而且这是最优的。我们把被覆盖的点都标记一下,然后找另外一个深度最大的没被覆盖的点,还是找他的第K个祖先建立消防站,然后看是不是每个点都被覆盖,如果是,表示这个K是可以的,否则K太小了。


代码:

#include <iostream>#include <cstdio>#include <cstring>#include <cassert>#include <queue>#include <cmath>#include <set>#include <algorithm>using namespace std;#define rep(i,a,b) for(int i=(a);i<(int)(b);++i)#define rrep(i,b,a) for(int i=(b);i>=(int)(a);--i)#define clr(a,x) memset(a,x,sizeof(a))#define eps 1e-8#define LL long long#define zero(x) (-eps < (x) && (x) < eps)#pragma comment(linker,"/STACK:102400000,102400000")const int maxn = 200000 + 5;int n;struct Node{int v;Node * next;}*first[maxn], edges[maxn * 2];int ptr;void add(int u, int v){edges[++ptr].v = v;edges[ptr].next = first[u];first[u] = &edges[ptr];}void input(){scanf("%d", &n);clr(first, 0);ptr = 0;rep(i, 1, n) {int u, v; scanf("%d%d", &u, &v);add(u, v); add(v, u);}}int q[maxn], fa[maxn];void bfs(){int front = 0, rear = 0;q[rear++] = 1; clr(fa, -1);while (front < rear) {int u = q[front++];for (Node * p = first[u]; p; p = p->next) {int v = p->v;if (v == fa[u]) continue;fa[v] = u; q[rear++] = v;}}}bool vis[maxn];int d[maxn];int Q[maxn];void Cover(int u, int limit){clr(d, 0x3f); d[u] = 0;int front = 0, rear = 0; Q[rear++] = u;while (front < rear) {u = Q[front++]; vis[u] = true;if (d[u] == limit) continue;for (Node * p = first[u]; p; p = p->next) {int v = p->v;if (d[v] <= d[u] + 1) continue;d[v] = d[u] + 1;Q[rear++] = v;}}}bool Ok(int limit, int & a, int & b){int cnt = 0;clr(vis, 0);rrep(i, n - 1, 0) {int u = q[i];if (vis[u]) continue;++cnt;if (cnt > 2) return false;rep(j, 0, limit) {if (fa[u] == -1) break;u = fa[u];}Cover(u, limit);if (cnt == 1) a = u;else b = u;}if (cnt == 1 || a == b) {if (a == 1) b = 2;else b = 1;}return true;}void solve(){bfs();int l = 0, r = n - 1, m;int sd = r + 11;int a, b;while (l <= r) {m = l + r >> 1;int u, v;if (Ok(m, u, v)) {if (m < sd)  {a = u; b = v;sd = m;}r = m - 1;}elsel = m + 1;}printf("%d %d %d\n", sd, a, b);}int main(){#ifdef ACMfreopen("in.txt", "r", stdin);#endif // ACMint T; cin >> T;while (T--) {input();solve();}}


C:Card Game

还没看。


D:Domination

题意:有一个N*M的棋盘,每天会在棋盘的所有未放棋子的格子中随机选择一个位置放置一个棋子,问棋盘要达到每行行列最少有一个棋子,平均需要放多少枚棋子。


思路:我们用dp[i][j][k] 表示已经放了i个棋子,有j行有棋子,有k列有棋子的概率。

注意其实选棋子就相当于选一个(r,c)的二元组。

我们能得到转移:dp[i+1][j][k] += dp[i][j][k] * (j * k - i) / (N * M - i);  (j * k - i >= 0) 

  意义:表示新选的棋子的行号和列号都已经选过了

                              dp[i+1][j+1][k] += dp[i][j][k] * (N-j) * k / ( N * M - i); 

                                  意义:表示新选的棋子的行号没选过,但是列号选过了。

                              dp[i+1][j][k+1] += dp[i][j][k] * j * (N - k) / (N*M - i);

                                   意义:表示新选的棋子的行号已经选过,但是列号没被选过。

                              dp[i+1][j+1][k+1] += dp[i][j][k] * (N - j) * (M - k) / (N * M - i);

      意义:表示新选的棋子的行号和列号均为被选过。

                              注意dp[i][N][M]不能进行转移,因为要求达到之后就不会再放棋子了。

最后我们的答案就是 sigma ( i * dp[i][N][M]) ( 1<=i<=N*M)

代码:

#include <iostream>#include <string.h>#include <cstring>#include <stdio.h>#define rep(i,a,b) for(int i=(a);i<(b);++i)#define rrep(i,b,a) for(int i = (b); i >= (a); --i)#define clr(a,x) memset(a,(x),sizeof(a))using namespace std;const int maxn = 50 + 5;double dp[maxn*maxn][maxn][maxn];int main(){int T; cin >> T;while (T--) {int N, M; scanf("%d%d", &N, &M);clr(dp, 0); dp[0][0][0] = 1.0;rep(i, 0, N*M) rep(j, 0, N + 1) rep(k, 0, M + 1) {if (j == N && k == M || dp[i][j][k] == 0) continue;if (j * k >= i) dp[i + 1][j][k] += dp[i][j][k] * (j*k - i) / (N*M - i);if (j + 1 <= N) dp[i + 1][j + 1][k] += dp[i][j][k] * (N - j) * k / (N*M - i);if (k + 1 <= M) dp[i + 1][j][k + 1] += dp[i][j][k] * j * (M - k) / (N*M - i);if (j + 1 <= N && k + 1 <= M) dp[i + 1][j + 1][k + 1] += dp[i][j][k] * (N - j) *(M - k) / (N*M - i);}double ans = 0;rep(i, 0, N*M+1) ans += i * dp[i][N][M];printf("%.10lf\n", ans);}}

E:Excavator ContestExcavator Contest


题意:从边界开始出发,每个格子均经过一次且仅一次,并且在边界停下来。


思路:....就是构造题嘛,有比较简单的构造办法,但是我的构造方法比较复杂,很不好写。

我说下我是怎么构造出来的。 假设我们已经求出了(N-2) * (N-2) 的行走方法,折数是(N-2) * (N-3) - 1.

我们就补上两行,两列,两行补在上方,两列补在右方,我们假设先走补上去的地方,如果补上去的地方能走出 N*(N-1) - 1 - (N-2)*(N-3) + 1 = 4 * N - 6, 就可以了。

其实这补上去的两行两列顶多只能走4 * N - 7个“折”, 问题来了:在哪里我们能多一个折呢? 就是从补上的地方进到之前就求出来的地方可以多一个“折”。这样就刚好能满足要求了。

我们需要根据N的奇偶分开来处理。我画几个图让大家看一下我的构造办法(我的方法是锻炼码力的方法再见)。

N = 10 的时候是酱紫的:

右边是大致的规律路线:


像根据这个10的怎么推出12的呢?我们只需要从右边多加两列,下面多加两行。然后从右上角往下,再往左,然后进入这个10x10的图里面就行了,你可以算一下,折数是刚好的。

N = 11 的时的图是酱紫的:


走法类似。

人工的走好像不难走,但是用代码感觉不好写啊。 我的做法是从左上角开始走一个类似回行的路径,然后从左下角开始也是走一个回行的路径。最后把还没走到的补上就行了。


代码:

#include <iostream>#include <string.h>#include <cstring>#include <stdio.h>#define rep(i,a,b) for(int i=(a);i<(b);++i)#define rrep(i,b,a) for(int i = (b); i >= (a); --i)#define clr(a,x) memset(a,(x),sizeof(a))using namespace std;const int maxn = 512 + 5;int N;int ans[maxn][maxn];int Move[2][4] = { { 1, 0, -1, 0 }, { 0, 1, 0, -1 } };int Act[4][4] = { { 0, 1, 2, 1 }, { 1, 0, 3, 0 }, { 3, 2, 1, 2 }, { 2, 3, 0, 3 } };int Do[2][4] = { { 0, 1, 2, 1 }, { 3, 0, 1, 0 } };bool inRange(int r, int c) { return 0 <= r && r < N && 0 <= c && c < N;  }void out(){rep(i, 0, N) rep(j,0,N) {if (j > 0) printf(" ");printf("%d", ans[i][j]);if (j == N - 1) puts("");}}bool Check(){int r = 0, c = 0;int turn = 0, dir = 0;rep(i, 1, N*N) {bool advance = false;if (r == 1 && c == 1)char a = 'a';rep(j, 0, 4) {int rr = r + Move[0][j];int cc = c + Move[1][j];if (!inRange(rr, cc) || ans[rr][cc] != i + 1) continue;r = rr; c = cc;if (dir != j) ++turn;dir = j;advance = true;break;}if (!advance) {return false;}}printf("%d %d\n", turn, N*(N - 1) - 1);return turn <= N*(N - 1) - 1;}int tmp[maxn][maxn];int main(){int T; cin >> T;while (T--) {scanf("%d", &N);if (N == 3) {puts("1 2 3");puts("8 7 4");puts("9 6 5");continue;}if (N & 1) {clr(ans, -1);int k = N / 2;int r = 0, c = 0;int step = 1;ans[r][c] = step++;for (; k > 0; ) {rep(j, 0, k) {ans[++r][c] = step++;ans[r][++c] = step++;ans[--r][c] = step++;ans[r][++c] = step++;}ans[++r][c] = step++;if (--k == 0) break;rep(j, 0, k) {ans[++r][c] = step++;ans[r][--c] = step++;ans[++r][c] = step++;ans[r][++c] = step++;}ans[++r][c] = step++;ans[r][--c] = step++;if (--k == 0) break;rep(j, 0, k) {ans[r][--c] = step++;ans[--r][c] = step++;ans[r][--c] = step++;ans[++r][c] = step++;}ans[r][--c] = step++;ans[--r][c] = step++;if (--k == 0) break;rep(j, 0, k) {ans[--r][c] = step++;ans[r][++c] = step++;ans[--r][c] = step++;ans[r][--c] = step++;}ans[--r][c] = step++;ans[r][++c] = step++;ans[r][++c] = step++;--k;//out();}step = N*N; r = N - 1; c = 0;ans[r][c] = step--;k = N / 2 - 1;for (; k > 0; ) {rep(j, 0, k) {ans[r][++c] = step--;ans[--r][c] = step--;ans[r][--c] = step--;ans[--r][c] = step--;}ans[r][++c] = step--;ans[r][++c] = step--;if (--k == 0) break;rep(j, 0, k) {ans[++r][c] = step--;ans[r][++c] = step--;ans[--r][c] = step--;ans[r][++c] = step--;}ans[++r][c] = step--;ans[++r][c] = step--;if (--k == 0) break;rep(j, 0, k) {ans[r][--c] = step--;ans[++r][c] = step--;ans[r][++c] = step--;ans[++r][c] = step--;}ans[r][--c] = step--;ans[r][--c] = step--;if (--k == 0) break;rep(j, 0, k) {ans[--r][c] = step--;ans[r][--c] = step--;ans[++r][c] = step--;ans[r][--c] = step--;}ans[--r][c] = step--;ans[--r][c] = step--;--k;}for (;;) {if (r - 1 >= 0 && ans[r - 1][c] == -1) ans[--r][c] = step--;else if (c + 1 < N && ans[r][c + 1] == -1) ans[r][++c] = step--;else if (r + 1 < N && ans[r + 1][c] == -1) ans[++r][c] = step--;else if (c -1 >= 0 && ans[r][c - 1] == -1) ans[r][--c] = step--;else break;}}else {clr(ans, -1);int k = N / 2 - 1;int r = 0, c = 0;int step = 1;ans[r][c] = step++;for (; k > 0;) {rep(j, 0, k) {ans[++r][c] = step++;ans[r][++c] = step++;ans[--r][c] = step++;ans[r][++c] = step++;}ans[r][++c] = step++;rep(j, 0, k) {ans[++r][c] = step++;ans[r][--c] = step++;ans[++r][c] = step++;ans[r][++c] = step++;}ans[++r][c] = step++;ans[r][--c] = step++;if ( (k -= 2) <= 0) break;rep(j, 0, k) {ans[r][--c] = step++;ans[--r][c] = step++;ans[r][--c] = step++;ans[++r][c] = step++;}ans[r][--c] = step++;ans[r][--c] = step++;rep(j, 0, k) {ans[--r][c] = step++;ans[r][++c] = step++;ans[--r][c] = step++;ans[r][--c] = step++;}ans[--r][c] = step++;ans[r][++c] = step++;ans[r][++c] = step++;k -= 2;//out();}int x = r, y = c, s = step;step = N*N; r = N - 1; c = 0;ans[r][c] = step--;k = (N-1) / 2 - 1;for (; k > 0;) {rep(j, 0, k) {ans[r][++c] = step--;ans[--r][c] = step--;ans[r][--c] = step--;ans[--r][c] = step--;}ans[--r][c] = step--;ans[r][++c] = step--;rep(j, 0, k) {ans[++r][c] = step--;ans[r][++c] = step--;ans[--r][c] = step--;ans[r][++c] = step--;}ans[++r][c] = step--;ans[++r][c] = step--;if ((k -= 2) <= 0) break;rep(j, 0, k) {ans[r][--c] = step--;ans[++r][c] = step--;ans[r][++c] = step--;ans[++r][c] = step--;}ans[++r][c] = step--;ans[r][--c] = step--;rep(j, 0, k) {ans[--r][c] = step--;ans[r][--c] = step--;ans[++r][c] = step--;ans[r][--c] = step--;}ans[--r][c] = step--;ans[--r][c] = step--;k -= 2;}r = x; c = y; step = s;for (;;) {if (r-1 >= 0 && ans[r - 1][c] == -1) ans[--r][c] = step++;else if (c + 1 < N && ans[r][c + 1] == -1) ans[r][++c] = step++;else if (r + 1 < N && ans[r + 1][c] == -1) ans[++r][c] = step++;else if (c - 1 >= 0 && ans[r][c - 1] == -1) ans[r][--c] = step++;else break;}}out();/*if (!Check()) {printf("Wrong\n");}*/}}


F:Fiber-optic Network

题意:有一颗树,要为每个节点赋一个值Fi,使得任意相邻的节点互素。然后对每个节点统计Fi在所有可能中的和。


思路:其实题目要求的就是对于每个点我们赋值为X的时候有多少种方案,然后每个点的答案就是 sigma(x * (对应方案数))。好了,我们的注意力转移到如何求方案数。

我们先看下当树是一条链的时候的情况,因为这种情况比较简单。 我们可以容易得到转移方程dp[i][j] = sigma(dp[i-1][k]) (k 与 j互素) 其中dp[i][j]表示前i个节点,第i个节点赋为j时的方案数。 但是显然复杂度已经是 50 * 50000 * 50000 ,太大了,不能忍!!而且我们能注意到其实互素的个数是很多的,我们不妨先求出跟j不是互素的,然后用总的减掉不是互素的方案数。如果是求不是互素要怎么求呢?我们能够用容斥,我的代码里貌似是类似莫比乌斯反演的东西? 我们把j进行分解素因子,然后枚举一下因子的组合容斥,选奇数个因子就是加上,偶数个就是减去(如果不懂我说什么可以先了解一下容斥的思想,并不是简单的全集减去对立面)。

如果要这么做,我们的状态的意义就要改一下了,这时候dp[i][j]中的j表示的是第i个节点的数字能被j整除时的方案数,我们继续注意到对每个赋的值x进行容斥统计的时候,我们只关注它有什么素因子,所以我们能继续把一些素因子完全一样的数一起进行统计。于是我们在节点i枚举每个素因子组成不同的数x来统计方案数S,然后把S加到每个dp[i][k] (k是x因子,因为我们的状态表示的是该位置的数字能被k整除时的方案数)。这样单链的情况我们基本就做出来了,当是树的时候一样的,只不过方案数是各个分支的方案数的乘积而已。

好了,现在如果知识要求出一个点Fi的和很简单是吧?但是题目要求所有的点的Fi和。我们当然可以直接以每个点作为根来做一遍dp,我这样做之间简单粗暴的返回tle。我们能不能把那个n*n的复杂度优化为n呢?是可以的。我们考虑一个题目:在一颗树里,求出每个点的最远节点的距离 。我们可以用dp[u][fa]表示在把(u,fa)这条边砍掉后,以u为根的子树中的“最远距离”,那么我们的递推就是dp[u][fa] = max(dp[v][u] + 1) (v是u的儿子)。 这里我们能够用记忆化搜索来做。 回到这道题,可以用一样的处理方法。不过直接多加一维会爆内存的,其实那个二维的状态我们可以用O(n)的空间存的,因为每一条边对应两个状态,所以状态数只有2*n-2. 我们另外开一个id[maxn][maxn]对状态进行标记就行了。具体的可以看代码。


代码:

#include <iostream>#include <vector>#include <algorithm>#include <string.h>#include <cstring>#include <stdio.h>#include <cmath>#include <math.h>#define rep(i,a,b) for(int i=(a);i<(b);++i)#define rrep(i,b,a) for(int i = (b); i >= (a); --i)#define clr(a,x) memset(a,(x),sizeof(a))#define LL long longusing namespace std;const int maxn = 50 + 5;const int maxv = 50000 + 5;const int mod = 1e9 + 7;LL num[maxn * 2][maxv];LL Count[maxn * maxn];int id[maxn][maxn];vector<int> pe[maxv];vector<int> fac[maxv];  int same[maxn][maxv];int h[maxv];int miu[maxv];int n;int l[maxn], r[maxn];vector<int> kind[maxn];vector<int> adj[maxn];void add(LL & a, LL b){a += b;if (a >= mod) a -= mod;}LL Cal_num(LL * arr, int x, LL amt){rep(i, 0, fac[x].size()) {int z = fac[x][i];amt += arr[z] * miu[z];if (amt >= mod) amt -= mod;if (amt < 0) amt += mod;}return amt;}bool vis[maxn][maxn];void dfs(int u, int fa){    if (vis[u][fa]) return;bool isleaf = true;vis[u][fa] = true;rep(i, 0, adj[u].size()) {int v = adj[u][i];if (v == fa) continue;isleaf = false;dfs(v, u);}if (isleaf) {rep(d, 0, kind[u].size()) {    int i = kind[u][d];rep(j, 0, fac[i].size()) {int x = fac[i][j];num[id[u][fa]][x] += same[u][i];}Count[id[u][fa]] += same[u][i];}}else {//统计方案数LL way;rep(e, 0,kind[u].size()) {int d = kind[u][e];way = same[u][d];rep(i, 0, adj[u].size()) {int v = adj[u][i];if (v == fa) continue;way = (way * Cal_num(num[id[v][u]], d, Count[id[v][u]])) % mod;}rep(j, 0, fac[d].size()) {int x = fac[d][j];add(num[id[u][fa]][x], way);}add(Count[id[u][fa]], way);}}}void solve(){    clr(id,-1);    clr(Count,0); clr(num,0); clr(vis,0);    int c = 0;    rep(i,1,n+1) {        rep(j,0,adj[i].size()) {            id[i][adj[i][j]] = ++c;        }//        id[i][i] = ++c;    }    rep(u,1,n+1) {        rep(j,0,adj[u].size()) {            int v = adj[u][j];            dfs(u,v);        }//        dfs(u,u);    }rep(u, 1, n + 1) {LL ans = 0;rep(i, l[u], r[u] + 1) {LL way = 1;rep(j, 0, adj[u].size()) {int v = adj[u][j];way = (way * Cal_num(num[id[v][u]], i, Count[id[v][u]])) % mod;}add(ans, way * i % mod);}if (u != 1) printf(" ");printf("%lld", ans);}puts("");}void read_int(int & x){    char ch = getchar();    while (ch < '0' || ch > '9') ch = getchar();    x = ch - '0'; ch = getchar();    while ('0' <= ch && ch <= '9') {        x = 10 * x + ch - '0';        ch = getchar();    }}void Getinput(){freopen("in.txt", "w", stdout);int T = 1; printf("%d\n", T);while (T--) {int n = 50; printf("%d\n", n);rep(i, 0, n) printf("1 ");puts("");rep(i, 0, n) printf("50000 ");puts("");rep(i, 0, n - 1) printf("%d %d\n", i + 1, i + 2);}}int main(){//Getinput(); return 0;//freopen("in.txt", "r", stdin);//    freopen("out.txt","w",stdout);rep(i, 1, maxv) {int x = i;if (~x & 1) {pe[i].push_back(2);while (~x & 1) x >>= 1;}for (LL j = 3; j*j <= x; j += 2) if (x % j == 0) {pe[i].push_back(j);do x /= j;while (x % j == 0);}if (x > 1) pe[i].push_back(x);//printf("%u\n", fac[i].size());int k = pe[i].size();int maxx = 1;rep(s, 1, 1 << k) {int x = 1;int odd = 0;rep(j, 0, k) if (s & (1 << j)) x *= pe[i][j], odd ^= 1;if (x > maxx) maxx = x;miu[x] = odd ? -1 : 1;fac[i].push_back(x);}h[i] = maxx;//printf("%u\n", fac[i].size());}int T; cin >> T;while (T--) {        read_int(n);//scanf("%d", &n);rep(i, 1, n + 1) read_int(l[i]); //scanf("%d", l + i);rep(i, 1, n + 1) read_int(r[i]); //scanf("%d", r + i);clr(same, 0);rep(i, 1, n + 1) {kind[i].clear();rep(j, l[i], r[i] + 1) {if (++same[i][h[j]] == 1) kind[i].push_back(h[j]);}//printf("%u\n",kind[i].size());}rep(i, 0, maxn) adj[i].clear();rep(i, 1, n) {int u, v; read_int(u); read_int(v); //scanf("%d%d", &u, &v);adj[u].push_back(v);adj[v].push_back(u);}solve();}}

G:Garden and Sprinklers

Garden and Sprinklers

Time Limit: 2 Seconds      Memory Limit: 65536 KB

There is a beautiful garden in Marjar University. Recently, Edward, the headmaster of Marjar University, decided to build a garden water sprinkler system. The system consists of three sprinklers.

Assuming that Marjar University is an infinite plane, the garden is a circle whose center is at (X0Y0) with radius R. Now, Edward has already determined the position for two sprinklers at (X1Y1) and (X2Y2). He needs to choose the position for the last sprinkler. Here are some conditions to be satisfied:

  1. The three sprinklers should not in the same line.
  2. The last sprinkler should be located inside or on the boundary of the garden.
  3. The coordinates of the sprinklers must be integers.
  4. Twice the area of the triangle that the three sprinklers form should equals S.

Under these conditions, Edward wants to know the number of possible positions for the last sprinkler. Please write a program to help him!

Input

There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:

The first line contains an integer S (1 <= S <= 108). The next line contains three integers X0Y0 and R (1 <= R <= 108). The last line contains four integers X1Y1X2and Y2.

It is guaranteed that the absolute value of all input coordinates will not exceed 108 and the positions of the two existing sprinklers are different.

Output

For each test case, output the number of possible positions.

Sample Input

140 0 4-1 0 1 0

Sample Output

14

Hint

In the sample test case, the possible positions for the last sprinkler are: (-3, 2), (-2, 2), (-1, 2), (0, 2), (1, 2), (2, 2), (3, 2), (-3, -2), (-2, -2), (-1, -2), (0, -2), (1, -2), (2, -2), (3, -2).



题意:给出一个圆,和圆内(上)两个不同的点,你要在圆内(上)找到第三个点(x,y)使得三个点形成的三角形的面积的两倍是S,而且x和y要是整数,问有多少个满足要求的点。


思路:其实题目本身不难,很多人都能想到,正因为这样,这题的正确率才落到2%..... 第一步是先将所有的点都平移一下吧,让圆的圆心在(0,0),然后我们把第三个点设为(x,y),那么现在有三个点的坐标,我们可以直接用叉乘来列出等式,有形如这样的|ax + by+c| = S, 也就是找

ax + by + c - S = 0的整数解和ax + by + c + S = 0的整数解。 其中x * x + y * y <= R * R .

那么我们把图画出来,就是一条直线与圆的关系,如果直线与圆相离,整数解为0. 如果是相切和相交,我们先用欧几里得算法求出一个可行解,然后在看有多少个解在圆内就行了。 

思路上就仅仅上面说的.....但是题目给的数有点大,运算的过程中频频溢出.....于是我用了Java .Orz. 用了Java发现不知道怎么求直线和圆的交点,因为通常解法是联立方程求解,会有一个取根号的运算....Java大数不知道怎么取根号....二分也行吧。不过我是先求出圆心到直线的垂心,然后就二分分别求出左交点的x坐标和右交点的x坐标,然后用扩展欧几里得求出可行解后,看有多少个解就行了......中间有好多边界没处理好,所以错了好多次.....如果自己做的时候觉得毫无破绽但是WA的,可以先写一个暴力的程序然后看看对不对,小一点的数据可以的话,一般都是可以的。另外,这个题目大概4W多组数据吧

具体的可以看代码,不过以前没怎么用过Java写题,可能下面的代码会很难看.....


代码:

<span style="font-size:18px;"><strong>import java.io.*;import java.util.*;import java.math.*;public class Main {public static void main(String [] args) throws IOException{Main body = new Main();Solver solver = body.new Solver();}public class Solver{StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));BigInteger x0,y0,x1,y1,x2,y2,R,S;BigInteger sqrR,sqrb,sqra,sqrc;long SS,x00,y00,x11,y11,x22,y22,RR;int BruteForce(){int ans = 0;long aa = a.longValue(), bb = b.longValue(), cc = c.longValue();if (aa == 0) {if (cc % bb != 0) return 0;else {long y = cc / bb;for(long x = -R.longValue(); x <= R.longValue(); ++x) {if (x*x + y*y <= sqrR.longValue()) ++ans;}}} else if (b.equals(ZERO())) {if (cc % aa != 0) return 0;else {long x = cc / aa;for(long y = -R.longValue(); y <= R.longValue(); ++y) {if (x*x+y*y<=sqrR.longValue()) ++ans;}}} else {for(long x = -R.longValue(); x <= R.longValue(); ++x) {if ((aa*x+cc)%bb != 0) continue;long y = aa*x + cc; y /= -bb;if (x*x + y*y <= sqrR.longValue()) {++ans;System.out.println(x);}}}return ans;}void input() throws IOException{cin.nextToken();S = valueOf((long)cin.nval);cin.nextToken();x00 = (long)cin.nval;cin.nextToken();y00 = (long)cin.nval;cin.nextToken();R = valueOf((long)cin.nval);cin.nextToken();x11 = (long)cin.nval;cin.nextToken();y11 = (long)cin.nval;cin.nextToken();x22 = (long)cin.nval;cin.nextToken();y22 = (long)cin.nval;x11 -= x00; y11 -= y00;x22 -= x00; y22 -= y00;}final BigInteger ZERO() { return BigInteger.ZERO; }final BigInteger ONE() { return BigInteger.ONE; }final BigInteger TWO() { return ONE().add(ONE()); }final BigInteger valueOf(long x) { return BigInteger.valueOf(x); }void gcd(BigInteger a,BigInteger b,BigInteger [] d, BigInteger [] x,BigInteger[]  y){if (b.equals(BigInteger.ZERO)) { d[0] = a; x[0] = BigInteger.ONE; y[0] = BigInteger.ZERO; }else {gcd(b,a.remainder(b),d,y,x);y[0] = y[0].subtract(x[0].multiply(a.divide(b)));}}final BigInteger sqr(BigInteger x) { return x.multiply(x); }BigInteger m,sqrRb,red;final void GetBound(BigInteger [] LL,BigInteger [] RR){BigInteger l = R.negate(),r = m;BigInteger x = ZERO(), dis = ZERO();BigInteger ac2 = a.multiply(c).multiply(TWO()); if (!red.equals(ZERO())) {if (ac2.negate().compareTo(ZERO()) < 0) r = r.subtract(ONE());}while (l.compareTo(r) <= 0) {x = (l.add(r)).divide(TWO());dis = sqra.add(sqrb).multiply(sqr(x));dis = dis.add(x.multiply(ac2));dis = dis.add(sqrc);if (dis.compareTo(sqrRb) > 0) l = x.add(ONE());else r = x.subtract(ONE());}LL[0] = l;l = m; r = R;//if (!a.multiply(c).remainder(sqra.add(sqrb)).equals(ZERO())) l = l.add(ONE()); if (!red.equals(ZERO())) {if (ac2.negate().compareTo(ZERO()) > 0) l = l.add(ONE());}while (l.compareTo(r) <= 0) {x = (l.add(r)).divide(TWO());dis = sqra.add(sqrb).multiply(sqr(x));dis = dis.add(x.multiply(ac2));dis = dis.add(sqrc);if (dis.compareTo(sqrRb) > 0) r = x.subtract(ONE());else l = x.add(ONE());}RR[0] = r;}BigInteger [] dd = new BigInteger[1];BigInteger [] xx = new BigInteger[1], yy = new BigInteger[1];BigInteger [] ll = new BigInteger[1], rr = new BigInteger[1];BigInteger a,b,c;BigInteger Cal(){if (sqrc.compareTo(sqrR.multiply(sqra.add(sqrb))) > 0) return ZERO();if (a.equals(ZERO())) {if (c.remainder(b).compareTo(ZERO()) != 0) return ZERO();else {BigInteger l = ZERO(),r = R;BigInteger y = c.divide(b);BigInteger sqry = sqr(y);while (l.compareTo(r) <= 0) {BigInteger x = (l.add(r)).divide(TWO());if (sqr(x).add(sqry).compareTo(sqrR) <= 0) l = x.add(ONE());else r = x.subtract(ONE());}return r.multiply(TWO()).add(ONE());}} else if (b.equals(ZERO())) {if (!c.remainder(a).equals(ZERO())) return ZERO();else {BigInteger l = ZERO(),r = R;BigInteger x = c.divide(a);BigInteger sqrx = sqr(x);while (l.compareTo(r) <= 0) {BigInteger y = (l.add(r)).divide(TWO());if (sqrx.add(sqr(y)).compareTo(sqrR) <= 0) l = y.add(ONE());else r = y.subtract(ONE());}return r.multiply(TWO()).add(ONE());}}BigInteger ans = ZERO();gcd(a,b,dd,xx,yy);BigInteger d = dd[0], x = xx[0];if (c.remainder(d).compareTo(ZERO()) != 0) return ZERO();x = x.multiply(c.divide(d)).negate();GetBound(ll,rr);BigInteger l = ll[0], r = rr[0];if (l.compareTo(r) > 0) return ZERO();BigInteger k = ZERO();d = b.divide(d);if (d.compareTo(ZERO()) < 0) d = d.negate();if (x.compareTo(l) > 0) {k = (l.subtract(x)).divide(d);x = x.add(k.multiply(d));}if (x.compareTo(l) < 0) {k = (l.subtract(x)).divide(d);x = x.add(k.multiply(d));while (x.compareTo(l) < 0) x = x.add(d);}if (r.compareTo(x) >= 0) k = ((r.subtract(x)).divide(d)).add(ONE());else k = ZERO();ans = k;return ans;}void solve(){a = valueOf(y11-y22); b = valueOf(x22-x11); c = valueOf(x11*y22-x22*y11);sqrR = sqr(R); sqra = sqr(a); sqrb = sqr(b);sqrRb = sqrR.multiply(sqrb);BigInteger sum = ZERO();c = c.add(S);sqrc = sqr(c);m = a.multiply(c).divide(sqra.add(sqrb)).negate();red = a.multiply(c).remainder(sqra.add(sqrb));sum = sum.add(Cal());//long std_ans = BruteForce();c = c.subtract(S.multiply(TWO()));sqrc = sqr(c);m = a.multiply(c).divide(sqra.add(sqrb)).negate();sum = sum.add(Cal());/*std_ans += BruteForce();if (sum.longValue() != std_ans) {System.out.println("Wrong answer");System.out.println(S);System.out.println(x00 + " " + y00 + " " + R);System.out.println( (x11 + x00) + " " + (y11+y00));System.out.println((x22+x00) + " " + (y22+y00));}out.println(std_ans);*/out.println(sum);out.flush();}Solver() throws IOException {cin.nextToken();int T; T = (int)cin.nval;for(int i = 0; i < T; ++i) {input();solve();}}}}/*1231000000000 0 10000000023 45 55 1001000000000 0 10000000023 45 2 10030 0 50 2-2 130 0 53 41 330 0 56 48 330 0 56 44 36090 0 253-217 195-216 01800 0 80-51 78-51 02550 0 2929 27-27 06090 0 253-217 195-216 0 */</strong></span>





H:Hierarchical Notation

Hierarchical Notation

Time Limit: 2 Seconds      Memory Limit: 131072 KB

In Marjar University, students in College of Computer Science will learn EON (Edward Object Notation), which is a hierarchical data format that uses human-readable text to transmit data objects consisting of attribute-value pairs. The EON was invented by Edward, the headmaster of Marjar University.

The EON format is a list of key-value pairs separated by comma ",", enclosed by a couple of braces "{" and "}". Each key-value pair has the form of "<key>":"<value>". <key> is a string consists of alphabets and digits. <value> can be either a string with the same format of <key>, or a nested EON.

To retrieve the data from an EON text, we can search it by using a key. Of course, the key can be in a nested form because the value may be still an EON. In this case, we will use dot "." to separate different hierarchies of the key.

For example, here is an EON text:

{"headmaster":"Edward","students":{"student01":"Alice","student02":"Bob"}}

  • For the key "headmaster", the value is "Edward".
  • For the key "students", the value is {"student01":"Alice","student02":"Bob"}.
  • For the key "students"."student01", the value is "Alice".

As a student in Marjar University, you are doing your homework now. Please write a program to parse a line of EON and respond to several queries on the EON.

Input

There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:

The first line contains an EON text. The number of colons ":" in the string will not exceed 10000 and the length of each key and non-EON value will not exceed 20.

The next line contains an integer Q (0 <= Q <= 1000) indicating the number of queries. Then followed by Q lines, each line is a key for query. The querying keys are in correct format, but some of them may not exist in the EON text.

The length of each hierarchy of the querying keys will not exceed 20, while the total length of each querying key is not specified. It is guaranteed that the total size of input data will not exceed 10 MB.

Output

For each test case, output Q lines of values corresponding to the queries. If a key does not exist in the EON text, output "Error!" instead (without quotes).

Sample Input

1{"hm":"Edward","stu":{"stu01":"Alice","stu02":"Bob"}}4"hm""stu""stu"."stu01""students"

Sample Output

"Edward"{"stu01":"Alice","stu02":"Bob"}"Alice"Error!


题意:给出一个"<key>":"<value>"对的字符串,然后询问某个key对应的value

思路:注意到我们能根据输入构造出一颗树的,我用Node表示树上的结点,每个Node里面是一个string key和map<string,Node*> value和value在输入的起始位置和结束位置。 这样询问的时候我们能从树的根开始往下走就行了。不过预处理感觉比较麻烦....注意输入有这种情况的 {"a":{}}  


代码:

<span style="font-size:18px;"><strong>#include <iostream>#include <vector>#include <algorithm>#include <string.h>#include <cstring>#include <stdio.h>#include <stack>#include <string>#include <map>#include <set>#include <cmath>#include <time.h>#include <cassert>#include <math.h>#define mp make_pair#define rep(i,a,b) for(int i=(a);i<(b);++i)#define rrep(i,b,a) for(int i = (b); i >= (a); --i)#define clr(a,x) memset(a,(x),sizeof(a))#define LL long long#define eps 1e-10#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define bit(x) (1LL<<(x))using namespace std;const int maxn = 50000+5;struct Node{    string key;    map<string,Node*> value;    int l,r;}src[maxn],*rt;int c;inline Node * new_node(){    src[++c].key = "";    src[c].value.clear();    return &src[c];}char in[maxn*20];char s[maxn*20];Node * fa[maxn];void input(){    c = 0; rt = new_node();    rt->key = ""; rt->value.clear();    scanf("%s",s);    memcpy(in,s,sizeof(s));    int len = strlen(s);    int t = 0; fa[t++] = rt;    string key = "";    Node * ch = rt;    vector<int> backup;    rep(i,0,len) {        if (s[i] == '"') {            ch = new_node();            fa[t++] = ch;            int j = i;            while (s[++i] != '"') ch->key += s[i];            if (t - 2 >= 0) fa[t-2]->value[ch->key] = ch;            if (s[i+1] == ',' || s[i+1] == '}') {                --t;                fa[t-1]->l = j;                fa[t-1]->r = i+1;            }        } else if (s[i] == '{') {            fa[t-1]->l = i;            backup.push_back(t);        }        else if (s[i] == '}') {            t = backup.back(); backup.pop_back();            fa[t-1]->r = i+1;        }        else if (s[i] == ',') {            --t;        }    }}void solve(){    int Q; scanf("%d",&Q);    while (Q--) {        scanf("%s",s);        int len = strlen(s);        string key = "";        Node * now = rt;        bool ok = true;        rep(i,0,len) {            if (s[i] == '"') {                key = "";                while (s[++i] != '"') key += s[i];                if (now->value.count(key) == 0) { puts("Error!"); ok = false; break; }                else now = now->value[key];            }        }        if (ok) {            int l = now->l, r = now->r;            char ch = in[r]; in[r] = '\0';            printf("%s\n",in+l);            in[r] = ch;        }    }}int main(){    int T; cin >> T;    while (T--) {        input();        solve();    }}</strong></span>

其他还没做
0 0
原创粉丝点击