# 2015 重庆市赛 解题报告

## A. 蠕虫爬井

0,n,1u,1d,$初始在0, 爬n高度的井, 爬1分钟u距离, 休息1分钟掉d距离, 问几分钟出井？$

d>=u,,$如果d>=u, 每次做无用功肯定爬不出去, 不然肯定可以出去$
,,,$最后一次可以直接出去, 所以先减去, 然后看剩下的要多久, 注意特判一开始直接出去的情况$

//
//  Created by TaoSama on 2015-11-18
//
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n, u, d;

int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);

while(scanf("%d%d%d", &n, &u, &d) == 3) {
if(u >= n) puts("1");
else if(u <= d) puts("The worm can't escape from the well.");
else {
int ans = 1;
n -= u; u -= d;
ans += (n + u - 1) / u * 2;
printf("%d\n", ans);
}
}
return 0;
}

## B. 回文数挑选

18$判断一个18位数字是否是回文数$

$签到题$

//
//  Created by TaoSama on 2015-11-19
//
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

char s[25];

int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);

while(scanf("%s", s) == 1) {
int n = strlen(s);
bool ok = true;
for(int i = 0; i < n >> 1; ++i) {
if(s[i] != s[n - i - 1]) {
ok = false;
break;
}
}
printf("%s ", s);
puts(ok ? "is a palindromic number." : "is not a palindromic number.");
}
return 0;
}

## C. 有趣的数字图形

$蛇形填数$

,$古老的模拟题了, 注意边界什么的就好$

//
//  Created by TaoSama on 2015-11-19
//
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n, a[15][15];

int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);

int kase = 0;
while(scanf("%d", &n) == 1) {
memset(a, 0, sizeof a);
int x, y, cnt = a[x = 1][y = 1] = 1;
while(cnt < n * n) {
while(y + 1 <= n && !a[x][y + 1]) a[x][++y] = ++cnt;
while(x + 1 <= n && !a[x + 1][y]) a[++x][y] = ++cnt;
while(y - 1 >= 1 && !a[x][y - 1]) a[x][--y] = ++cnt;
while(x - 1 >= 1 && !a[x - 1][y]) a[--x][y] = ++cnt;
}
if(kase++) puts("");
for(x = 1; x <= n; ++x) {
for(y = 1; y <= n; ++y)
printf("%3d", a[x][y]);
puts("");
}
}
return 0;
}

## D. 奇怪的木匠

[0,10],5,,,$求一个长宽高为[0,10], 小数位数最多为5位浮点数的立方体, 切成小正方体, 求最少能切多少个, 不能有剩余$

gcdgcd,,int$求个gcd就是最小的gcd, 浮点有误差读字符串转化一下, 注意会炸int$

//
//  Created by TaoSama on 2015-11-19
//
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

typedef long long LL;

LL n, a, b, c, OFF = 1e5;
string l, w, h;

LL ten(int x) {
LL ret = 1;
for(int i = 1; i <= x; ++i) ret *= 10;
return ret;
}

void handle(string &l, LL& a) {
if(l.find('.') == string::npos) {
a = atoi(l.c_str()) * OFF;
return;
}
int p = l.find('.'); l.erase(p, 1);
a = atoi(l.c_str()) * ten(5 - (l.size() - p));
}

int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);

int t; cin >> t;
while(t--) {
cin >> l >> w >> h;
handle(l, a);
handle(w, b);
handle(h, c);
LL each = __gcd(a, __gcd(b, c));
LL ans = a * b * c / (each * each * each);
cout << ans << '\n';
}
return 0;
}

## E. 加倍或清0

,,线,,线$两行整数, 相等的数可以匹配, 求交叉线段的个数, 一个数只能匹配被一次, 交叉的线段的两段数不能是相同的数$

dp[i][j]:=i,j$显然的状态dp[i][j]:= 第一行匹配到第i个, 第二行匹配到第j个的最大匹配数$
O(n2),O(1),,$由于暴力转移的决策数是O(n^2)的, 显然本题需要O(1)的转移, 观察可以发现, 最近的决策一定是最优的$
,$越近的话, 之前匹配的越多$

dp[i][j]a[i]<jdown[i][j]$考虑预处理在dp[i][j]状态下第二行与a[i]相同的
dp[i][j]b[j]<iup[i][j]$同理在在dp[i][j]状态下第一行与b[j]相同的
,,O(1)$然后转移就好了, 需要注意的时候每次需要取到之前最优的状态, 不然没法取最近的决策来O(1)转移$

//
//  Created by TaoSama on 2015-11-19
//
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e3 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n, m, a[N], b[N];
int dp[N][N], down[N][N], up[N][N];

int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);

int t; scanf("%d", &t);
while(t--) {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) scanf("%d", a + i);
for(int i = 1; i <= m; ++i) scanf("%d", b + i);

for(int i = 2; i <= n; ++i) {
for(int j = 2; j <= m; ++j) {
if(a[i] == b[j - 1]) down[i][j] = j - 1;
else down[i][j] = down[i][j - 1];
}
}
for(int i = 2; i <= n; ++i) {
for(int j = 2; j <= m; ++j) {
if(b[j] == a[i - 1]) up[i][j] = i - 1;
else up[i][j] = up[i - 1][j];
}
}

for(int i = 2; i <= n; ++i) {
for(int j = 2; j <= m; ++j) {
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
if(a[i] == b[j]) continue;
int a = down[i][j], b = up[i][j];
if(a && b) dp[i][j] = max(dp[i][j], dp[b - 1][a - 1] + 2);
}
}
printf("%d\n", dp[n][m]);
}
return 0;
}

## F. 三角形中的格点

pick:S=a+b÷21abs$考虑pick定理: 顶点在格点上的多边形面积公式：S=a+b÷2-1，其中a表示多边形内部的点数，b表示多边形边界上的点数，s表示多边形的面积$
a,22:2a=2S+2b$我们需要求a, 由于有除2我们全部乘2得到: 2a = 2S+2-b$
,b(),gcd(x,y)1$三角形面积可以用向量叉积来做, b的话三角形边上的点(不考虑端点), 可以用gcd(x, y)-1来求$
$问题解决$

abs,gcd$注意abs啊, gcd和求三角形面积的时候都需要注意$

//
//  Created by TaoSama on 2015-11-19
//
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

struct Point {
int x, y;
Point operator- (const Point& p) const {
return (Point) {x - p.x, y - p.y};
}
int operator^(const Point& p) const {
return x * p.y - y * p.x;
}
} a[3];

int getArea2() {
return (a[1] - a[0]) ^ (a[2] - a[0]);
}

int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);

while(true) {
bool ok = false;
for(int i = 0; i < 3; ++i) {
if(a[i].x || a[i].y) ok = true;
}
if(!ok) break;

//pick theorem S = in + side/2 - 1
int s = abs(getArea2()), side = 3;
for(int i = 0; i < 3; ++i) {
Point t = a[i] - a[(i + 1) % 3];
side += abs(__gcd(t.x, t.y)) - 1;
}
int ans = s + 2 - side >> 1;
printf("%d\n", ans);
}
return 0;
}

## G. Cross a Lake

N105,2,H,9901$N\leq10^5的序列, 选出有\geq2个元素的子序列, 且相邻元素差值不超过H的子序列个数, 答案模9901$

dp,dp[i]:=a[i]$显然的dp, dp[i]:= 以a[i]结尾的满足要求的子序列个数$
dp[i]=dp[j]++dp[k]+1,dp[j]a[i]h,dp[k]a[i]+h$dp[i]=dp[j]+\cdots+dp[k] +1, dp[j]为以a[i]-h的结尾的, dp[k]为以a[i]+h的结尾的满足要求的子序列个数$
1,O(n),,BITdp[i],O(logn)$多1个是只有自己的情况, 显然转移是O(n)的不行, 由于是个区间和, 我们可以考虑用BIT来维护dp[i]的前缀和, 就可以在O(logn)转移了$
,$数字太大, 我们需要离散化$
12,n1$由于只有1个的情况是不行的题目要求\geq2个元素的子序列, 最终答案还需要减去n个1个元素的子序列$

,,ans=((xy)%MOD+MOD)%MOD$由于有负数, 而且模数太小, 所以需要ans = ((x-y)\%MOD+MOD)\%MOD$

//
//  Created by TaoSama on 2015-11-19
//
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 9901;

int n, h, a[N], b[N];

void add(int i, int v) {
for(; i <= n; i += i & -i) b[i] += v;
}

int sum(int i) {
int ret = 0;
for(; i; i -= i & -i) ret += b[i];
return ret;
}

int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);

while(scanf("%d%d", &n, &h) == 2) {
vector<int> xs;
for(int i = 1; i <= n; ++i) {
scanf("%d", a + i);
xs.push_back(a[i]);
}
sort(xs.begin(), xs.end());
xs.resize(unique(xs.begin(), xs.end()) - xs.begin());

memset(b, 0, sizeof b);
for(int i = 1; i <= n; ++i) {
int o = lower_bound(xs.begin(), xs.end(), a[i]) - xs.begin() + 1;
int l = lower_bound(xs.begin(), xs.end(), a[i] - h) - xs.begin() + 1;
int r = upper_bound(xs.begin(), xs.end(), a[i] + h) - xs.begin();
int tmp = (sum(r) - sum(l - 1)) % MOD;
}
int ans = ((sum(n) - n) % MOD + MOD) % MOD;
printf("%d\n", ans);
}
return 0;
}

## H. A Pilot in Danger

(0,0)n16,px+qy(x,y0, 2p,q1000),safe$求点(0,0)是否在n\leq16个点的任意多边形内, 在就输出px+qy不能构成数的个数 (x, y\geq0,\ 2\leq p, q\geq1000的素数), 不能就输出safe$

ans=(p1)(q1)/2$第二问ans = (p-1)(q-1)/2$ 证明见: 戳我看证明
,pq,使exgcd$赛后数据加强了, 赛上大胆猜想 \geq p*q 一定可以被构造, 可以使用exgcd求出一组解$
pq,,$然后暴力p*q范围内有多少个不可能构成, 也可以藉此来找出规律, 找到结论$

//
//  Created by TaoSama on 2015-11-19
//
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
const double EPS = 1e-8;

int n;

int sgn(double x) {return x < -EPS ? -1 : x < EPS ? 0 : 1;}

struct Point {
double x, y, ang;
Point(double x = 0, double y = 0): x(x), y(y) {}
void read() {scanf("%lf%lf", &x, &y); ang = atan2(y, x);}
Point operator- (const Point& p) const {
return (Point) {x - p.x, y - p.y};
}
double operator* (const Point& p) const {
return x * p.x + y * p.y;
}
double operator^ (const Point& p) const {
return x * p.y - y * p.x;
}
bool operator< (const Point& p) const {
return ang < p.ang;
}
} a[20];

bool onSeg(Point p, Point a, Point b) {
return sgn((a - p ^ b - p) == 0 && sgn((a - p) * (b - p)) <= 0);
}

int isPointInPolygon(Point p) {
int wn = 0;
for(int i = 0; i < n; ++i) {
if(onSeg(p, a[i], a[i + 1])) return -1;
int k = sgn(a[i + 1] - a[i] ^ p - a[i]);
int d1 = sgn(a[i].y - p.y);
int d2 = sgn(a[i + 1].y - p.y);
if(k > 0 && d1 <= 0 && d2 > 0) ++wn;
if(k < 0 && d2 <= 0 && d1 > 0) --wn;
}
if(wn != 0) return 1;
return 0;
}

int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);

int kase = 0;
while(scanf("%d", &n) == 1 && n) {
for(int i = 0; i < n; ++i) a[i].read();
int p, q; scanf("%d%d", &p, &q);
a[n] = a[0];

printf("Pilot %d\n", ++kase);
if(isPointInPolygon(Point(0, 0)) == 0) {
puts("The pilot is safe.\n");
continue;
}
puts("The pilot is in danger!");
printf("The secret number is %d.\n\n", (p - 1) * (q - 1) >> 1);
}
return 0;
}

• 本文已收录于以下专栏：

## 2015重庆市赛总结

• zyd8888102
• 2015年11月19日 20:15
• 617

## 2015ACM浙江省省赛部分题解

The 12th Zhejiang Provincial Collegiate Programming Contest总体感觉题目有大概7道不涉及算法的题目。听群里讨论，现场赛有队伍一小时ac了7道题...
• u013077144
• 2016年04月21日 19:00
• 1444

## 2016ACM省赛总结

• huatian5
• 2016年06月07日 15:20
• 1902

## NOIp2015提高组 解题报告

• jr_mz
• 2015年12月03日 18:34
• 3871

## 2017年广东ACM省赛 I题 解题报告

• li_wei_quan
• 2017年05月08日 22:23
• 887

## NOIP 2015模拟赛 题解&总结

• getsum
• 2016年11月11日 21:13
• 583

## 西南科技大学 信息工程学院 院赛 部分题题解，持续更新.

【萌萌院赛之A】 【题目链接】点击打开链接 【题意】由于中文题目，就不说题意！ 【解题思路】简单求根公式的应用！ 【AC代码】 #include typedef long long LL; cons...
• just_sort
• 2016年06月05日 21:03
• 865

## NOI 2015 滞后赛解题报告

• Lcomyn
• 2015年08月14日 15:38
• 1150

## 2015-2016 ACM-ICPC Pacific Northwest Regional Contest Div.2 全部题目题解

• Kiritow
• 2016年08月15日 21:29
• 999

## hihoCoder1252 2015北京区域赛 D.Kejin Game

• tianji_fange_tuhao
• 2016年06月02日 12:06
• 582

举报原因： 您举报文章：2015 重庆市赛 解题报告 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)