【2017.10.25】noip赛前集训 | T1画方框【暴力解题】、T2买西瓜【DP】、T3蚂蚁路径【组合数 + 容斥原理】
T1画方框
【问题描述】
在前面的游戏中,由于 moreD 每次都用最优策略赢了他的宠物 CD,CD 现在很郁闷,于 是他一个人在地板上画画东西了。别人都是说,“画个圈圈诅咒你”,但是 CD 很有特点,他 喜欢“画个框框诅咒你……”。 现在我们把 CD 画的东西记录到一个 N×N 方阵上了,1 表示 CD 画过的地方,0 表示空 白,请问 CD 最多可能画了多少不重复个方框呢? 方框就是所有以 1 为边的正方形,最小的方框是一个 1,CD 画方框的时候,是完全可 能把两个不一样的方框的某些边重复画到同一个位置上的。参见样例。
【数据描述】
对于 30%的数据 N<=100。
对于 50%的数据 N<=500。
对于 100%的数据 N<=1000。
【题解】
大暴力,听说 n3 就可以AC这道题。

#include <cstdio> const int MAXN = 1000 + 7; int n, ans; bool mx[MAXN][MAXN]; bool check(int x, int y, int len) { for (int i = x; i <= len + x - 1; i++) if (!mx[i][y] || !mx[i][y + len - 1]) return 0; for (int i = y; i <= len + y - 1; i++) if (!mx[x][i] || !mx[x + len - 1][i]) return 0; return 1; } int read() { int x = 0; char ch = getchar(); while (ch < '0' || ch > '9') ch = getchar(); while (ch <= '9' && ch >= '0') x = x * 10 + ch - 48, ch = getchar(); return x; } int main() { freopen("matrix.in", "r", stdin); freopen("matrix.out", "w", stdout); n = read(); for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) { mx[i][j] = read(); } // for (int i = 1; i <= n; i++) { // for (int j = 1; j <= n; j++) printf( mx[i][j] == 1 ? "1 " : "0 "); // printf("\n"); // } // for (int len = 1; len <= n; len++) for (int i = 1; i + len - 1 <= n; i++) for (int j = 1; j + len - 1 <= n; j++) { if (!mx[i][j]) continue; if (check(i, j, len)) ans++; } printf("%d\n", ans); return 0; }
是我没写对还是啥的,以上代码只过了3个点。
T2 买西瓜
【题意】
暑假大家在这里集训都很辛苦吧,买汽水怎么够呢,symbol 又准备给大家买西瓜消暑 啦,刚刚你就拼命花最多的钱,这次每天都可以吃西瓜,但你得保证花的钱最少…… 假设我们集训 N 天,第 i 天西瓜一个 Pi 元并且能吃 Di 天。每天我们最多能买一个西 瓜,要是买西瓜那天我们已经有西瓜了,如果又买一个,那么之前那个即使没吃完也得扔 掉。 在保证我们每天都能吃到西瓜的情况下,我们最少要花多少钱呢?
【数据描述】
对于 50%的数据,n<=500;
对于 80%的数据,n<=30000;
对于 100%的数据,n<=50000。
【题解】
一道DP。
设 f [ i ] 表示前 i - 1 天都有西瓜吃,第 i 天再买个西瓜(大概......)。
那我们就得到状态转移方程 f [ i ] = std::min( f [ i ], f [ j ]);
具体代码: 团长太神了!!!!%%%%%dalao
View Code#include <cstdio> #include <algorithm> const int MAXN = 5e4 + 7; int n, w[MAXN], v[MAXN], maxn, f[MAXN]; int main() { // freopen("watermelon.in", "r", stdin); // freopen("watermelon.out", "w", stdout); scanf("%d", &n); for (int i = 1; i <= n; i++) f[i] = 0x7fffffff; for (int i = 1; i <= n; i++) scanf("%d", &w[i]); for (int j = 1; j <= n; j++) { scanf("%d", &v[j]); if (maxn < v[j]) maxn = v[j]; } f[1] = w[1]; for (int i = 2; i <= n; i++) { for (int k = 1, j = i - k ; k <= maxn && j > 0; k++, j = i - k) { if (j + v[j] >= i) f[i] = std::min(f[i], f[j]); } f[i] += w[i]; } // for (int i = 1; i <= n; i++) printf("%d ", f[i]); int ans = 0x7fffffff; for (int k = 0, j = n - k ; k <= maxn && j >= 0; k++, j = n - k) { if (j + v[j] - 1 >= n) ans = std::min(ans, f[j]); } printf("%d\n", ans); return 0; }
T3 蚂蚁路径
【问题描述】
汽水和西瓜真的是人见人爱啊,Symbol 发现蚂蚁也来了,两只蚂蚁分别从两个位置出 发分别走到汽水和西瓜所在的地方: 蚂蚁 A 在坐标(0,0)的位置,B 在(p,0),A 要走到(m,n),B 要走到(m,q),其中 m,n,p,q 都 是小于 100000 的正整数,且(p < m , q < n)。蚂蚁只能沿着坐标系中整数组成的网格向 x 轴或者 y 轴的正方向爬行。请问,两只蚂蚁路径不重叠(两个路径没有相交的地方)的情 况有多少种?
【数据范围】
对于 50%的数据 m+n 小于 20。
对于 70%的数据 m+n 小于 20000。
对于 100%的数据 m+n 小于 200000。
提示:20! = 2432902008176640000 < 2^63。
【题解】
组合数 + 容斥原理