题目涉及算法:

  • 乒乓球:简单字符串模拟;
  • 数字游戏:区间DP;
  • 栈:卡特兰数
  • 麦森数:高精度、快速幂、数学。

乒乓球

题目链接:https://www.luogu.org/problem/P1042

这道题目是一道较为繁琐的字符串模拟,有点烦但是并不难。

我的代码的思想是将到‘E’为止的输入全部存到一个字符串中,然后遍历字符串,用win_point来存放赢的分数,用lose_point来存放对手赢的分数,如果满足条件 (win_point>=11 || lose_point>=11) && abs(win_point-lose-point)>=2 ,则说明一局结束了(21分制同理)。

这里需要注意的一点是:我最后还是需要输出当前这一句目前的比分(是‘0:0’也要输出)。

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
char s[1000000], c;
int n, win_point, lost_point;
int main() {
while ((c = getchar()) != 'E') {
if (c == 'W' || c == 'L') s[n++] = c;
}
for (int i = 0; i < n; i ++) {
s[i] == 'W' ? win_point ++ : lost_point ++;
if ((win_point >= 11 || lost_point >= 11) && abs(win_point-lost_point) >= 2) {
cout << win_point << ":" << lost_point << endl;
win_point = lost_point = 0;
}
}
cout << win_point << ":" << lost_point << endl;
cout << endl;
win_point = lost_point = 0;
for (int i = 0; i < n; i ++) {
s[i] == 'W' ? win_point ++ : lost_point ++;
if ((win_point >= 21 || lost_point >= 21) && abs(win_point-lost_point) >= 2) {
cout << win_point << ":" << lost_point << endl;
win_point = lost_point = 0;
}
}
cout << win_point << ":" << lost_point << endl;
return 0;
}

数字游戏

题目链接:https://www.luogu.org/problem/P1043

这道题目涉及知识点:区间DP。

这里面涉及一个环,但是我们可以拆开这个环。

我们假设输入的是 \(a_1 , \dots , a_n\) ,那么我们可以

  • 令 \(sum[i]\) 表示 \(a_1 + \dots + a_i\)
  • 令 \(maxv[i][j][k]\) 表示区间 \([i,j]\) 范围分成 \(k\) 份能够获得的最大乘积;
  • 令 \(maxv[i][j][k]\) 表示区间 \([i,j]\) 范围分成 \(k\) 份能够获得的最大乘积

可以得到状态转移方程如下:

\(maxv[i][j][k] = max(maxv[i][j][k], maxv[i][l][k-1] * get_mod(sum[j]-sum[l]) )\)

\(minv[i][j][k] = min(minv[i][j][k], minv[i][l][k-1] * get_mod(sum[j]-sum[l]) )\)

其中,\(get_mod(a)\) 用于获得 \(a \mod 10\) 的结果。

然后:

最大值就是 \(maxv[1][n][m]\) 和所有满足条件的 \(maxv[i][j][m-1] * get_mod(sum[i-1] + sum[n] - sum[j])\) 中的最大值;

最小值就是 \(minv[1][n][m]\) 和所有满足条件的 \(minv[i][j][m-1] * get_mod(sum[i-1] + sum[n] - sum[j])\) 中的最小值。

这样就解决了环的问题,因为最外面的环肯定最多只占一段。

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 55;
int n, m, a[maxn], sum[maxn];
long long maxv[maxn][maxn][10], minv[maxn][maxn][10], max_ans, min_ans;
long long get_mod(long long a) {
return (a % 10 + 10) % 10;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
sum[i] = sum[i-1] + a[i];
}
if (m == 1) {
cout << get_mod(sum[n]) << endl;
cout << get_mod(sum[n]) << endl;
return 0;
}
for (int k = 1; k <= m; k ++) {
for (int i = 1; i+k-1 <= n; i ++) {
for (int j = i+k-1; j <= n; j ++) {
if (k == 1) {
maxv[i][j][k] = get_mod(sum[j] - sum[i-1]);
minv[i][j][k] = get_mod(sum[j] - sum[i-1]);
}
else { // k > 1
for (int l = i+k-2; l < j; l ++) {
maxv[i][j][k] = max(maxv[i][j][k], maxv[i][l][k-1] * get_mod(sum[j]-sum[l]) );
minv[i][j][k] = min(minv[i][j][k], minv[i][l][k-1] * get_mod(sum[j]-sum[l]) );
}
}
}
}
}
max_ans = maxv[1][n][m];
min_ans = minv[1][n][m];
for (int i = 1; i <= n-m+1; i ++) {
for (int j = i+m-2; j <= n; j ++) {
max_ans = max(max_ans, maxv[i][j][m-1] * get_mod(sum[i-1] + sum[n] - sum[j]) );
min_ans = min(max_ans, minv[i][j][m-1] * get_mod(sum[i-1] + sum[n] - sum[j]) );
}
}
cout << min_ans << endl;
cout << max_ans << endl;
return 0;
}

题目描述:https://www.luogu.org/problem/P1044

这道题目就是一道“卡特兰数”,我时直接套公式做的(当然也有递推公式),公式如下:

\(Ci = \frac1{n+1}C_{2n}^n\)

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
int n;
long long m1 = 1, m2 = 1, tmp;
int main() {
cin >> n;
for (int i = n; i >= 1; i --) {
m1 *= i+n;
m2 *= i;
tmp = __gcd(m1, m2);
m1 /= tmp;
m2 /= tmp;
}
m1 /= n+1;
cout << m1 << endl;
return 0;
}

麦森数

题目链接:https://www.luogu.org/problem/P1045

这道题目一眼看过去就是高精度+快速幂。

这里有一个优化,就是长度,因为是2进制的P位数,并且它在十进制下不会是连续的全都是 \(9\) ,所以 \(2^P-1\) 肯定和 \(2^P\) 具有相同的位数。

所以长度可以直接通过公式 \(\lceil P \times \frac{\log 2}{\log 10} \rceil\) 获得。

然后最暴力的快速幂高精度幂是会超时的,但是如果我们在运算过程中保证因数的长补不超过500(截取末尾500位),就不会超时。

(然后我因为年纪比较大了,所以高精度运算直接搬了我之前写的模板囧~ 所以大家还是只看主函数就好了, multi 函数就是高精度乘, Sub函数就是高精度减)

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10000010; int a[maxn], b[maxn], res[maxn]; string add(string s1, string s2) { // under condition: s1,s2>=0
// 初始化部分
int n = s1.length(), m = s2.length();
for (int i = 0; i < n; i ++) a[i] = s1[n-1-i] - '0';
for (int i = 0; i < m; i ++) b[i] = s2[m-1-i] - '0';
int len = max(n, m) + 1;
for (int i = n; i < len; i ++) a[i] = 0;
for (int i = m; i < len; i ++) b[i] = 0;
for (int i = 0; i < len; i ++) res[i] = 0;
// 处理部分
for (int i = 0; i < len; i ++) {
res[i] += a[i] + b[i];
if (res[i] >= 10) {
res[i+1] += res[i] / 10;
res[i] %= 10;
}
}
// 返回部分
int i = len-1;
while (res[i] == 0 && i > 0) i --;
string s = "";
for (; i >= 0; i --) {
char c = (char) (res[i] + '0');
s += c;
}
return s;
} string sub(string s1, string s2) { // under condition: s1>=s2>=0
// 初始化部分
int n = s1.length(), m = s2.length();
for (int i = 0; i < n; i ++) a[i] = s1[n-1-i] - '0';
for (int i = 0; i < m; i ++) b[i] = s2[m-1-i] - '0';
int len = max(n, m);
for (int i = n; i < len; i ++) a[i] = 0;
for (int i = m; i < len; i ++) b[i] = 0;
for (int i = 0; i < len; i ++) res[i] = 0;
// 处理部分
for (int i = 0; i < len; i ++) {
res[i] += a[i] - b[i];
if (res[i] < 0) {
res[i+1] --;
res[i] += 10;
}
}
// 返回部分
int i = len-1;
while (res[i] == 0 && i > 0) i --;
string s = "";
for (; i >= 0; i --) {
char c = (char) (res[i] + '0');
s += c;
}
return s;
} bool cmp(string s1, string s2) { // under condition: s1,s2 >= 0
int n = s1.length(), m = s2.length();
int i;
for (i = 0; i < n-1 && s1[i] == '0'; i ++);
s1 = s1.substr(i);
for (i = 0; i < m-1 && s2[i] == '0'; i ++);
s2 = s2.substr(i);
if (s1.length() != s2.length()) return s1.length() < s2.length();
return s1 < s2;
} string Add(string s1, string s2) {
if (s1[0] == '-' && s2[0] == '-') {
return "-" + add(s1.substr(1), s2.substr(1));
}
else if (s1[0] == '-') {
s1 = s1.substr(1);
if (cmp(s1, s2) == true) {
return sub(s2, s1);
} else {
return "-" + sub(s1, s2);
}
}
else if (s2[0] == '-') {
s2 = s2.substr(1);
if (cmp(s1, s2) == true) {
return "-" + sub(s2, s1);
} else {
return sub(s1, s2);
}
}
else {
return add(s1, s2);
}
} string Sub(string s1, string s2) {
if (s2[0] == '-') {
s2 = s2.substr(1);
return Add(s1, s2);
}
else {
return Add(s1, "-" + s2);
}
} string multi(string s1, string s2) { // under condition: s1,s2>=0
// 初始化部分
int n = s1.length(), m = s2.length();
for (int i = 0; i < n; i ++) a[i] = s1[n-1-i] - '0';
for (int i = 0; i < m; i ++) b[i] = s2[m-1-i] - '0';
int len = n + m;
for (int i = n; i < len; i ++) a[i] = 0;
for (int i = m; i < len; i ++) b[i] = 0;
for (int i = 0; i < len; i ++) res[i] = 0;
// 处理部分
for (int i = 0; i < n; i ++)
for (int j = 0; j < m; j ++)
res[i+j] += a[i] * b[j];
for (int i = 0; i < len; i ++) {
res[i+1] += res[i] / 10;
res[i] %= 10;
}
// 返回部分
int i = len-1;
while (res[i] == 0 && i > 0) i --;
string s = "";
for (; i >= 0; i --) {
char c = (char) (res[i] + '0');
s += c;
}
return s;
} pair<string, string> divide(string s1, string s2) { // under condition: s1>=0,s2>0
string s = "", t = "";
int n = s1.length(), m = s2.length();
bool flag = false;
for (int i = 0; i < n; i ++) {
s += s1[i];
int num = 0;
while (cmp(s, s2) == false) {
num ++;
s = sub(s, s2);
}
if (num > 0) {
flag = true;
char c = (char)(num + '0');
t += c;
}
else if (flag) {
t += '0';
}
}
if (t.length() == 0) t = "0";
while (s[0] == '0' && s.length() > 1) s = s.substr(1);
return make_pair(t, s);
} string s = "2", t = "1", ans = "";
int P; int main() {
cin >> P;
int ans_len = ceil(P * log(2) / log(10));
cout << ans_len << endl;
while (P > 1) {
if (P % 2) {
t = multi(t, s);
if (t.length() > 500) t = t.substr(t.length()-500, 500);
}
s = multi(s, s);
if (s.length() > 500) s = s.substr(s.length()-500, 500);
P /= 2;
}
s = multi(s, t);
s = Sub(s, "1");
int len = s.length();
if (len <= 500) for (int i = 0; i < 500 - len; i ++) ans += "0";
if (len <= 500)
ans += s;
else
ans = s.substr(len-500, 500);
for (int i = 0; i < 10; i ++) cout << ans.substr(i*50, 50) << endl;
return 0;
}

2003年NOIP普及组复赛题解的更多相关文章

  1. 2010年NOIP普及组复赛题解

    题目及涉及的算法: 数字统计:入门题: 接水问题:基础模拟题: 导弹拦截:动态规划.贪心: 三国游戏:贪心.博弈论. 数字统计 题目链接:洛谷 P1179 这道题目是一道基础题. 我们只需要开一个变量 ...

  2. 2017年NOIP普及组复赛题解

    题目涉及算法: 成绩:入门题: 图书管理员:模拟: 棋盘:最短路/广搜: 跳房子:RMQ/二分答案/DP(本人解法). 成绩 题目链接:https://www.luogu.org/problemnew ...

  3. 2016年NOIP普及组复赛题解

    题目涉及算法: 买铅笔:入门题: 回文日期:枚举: 海港:双指针: 魔法阵:数学推理. 买铅笔 题目链接:https://www.luogu.org/problem/P1909 设至少要买 \(num ...

  4. 2014年NOIP普及组复赛题解

    题目涉及算法: 珠心算测验:枚举: 比例简化:枚举: 螺旋矩阵:模拟: 子矩阵:状态压缩/枚举/动态规划 珠心算测验 题目链接:https://www.luogu.org/problem/P2141 ...

  5. 2013年NOIP普及组复赛题解

    题目涉及算法: 计数问题:枚举: 表达式求值:栈: 小朋友的数字:动态规划: 车站分级:最长路. 计数问题 题目链接:https://www.luogu.org/problem/P1980 因为数据量 ...

  6. 2011年NOIP普及组复赛题解

    题目涉及算法: 数字反转:模拟: 统计单词数:模拟: 瑞士轮:模拟/排序: 表达式的值:后缀表达式/DP. 数字反转 题目链接:https://www.luogu.org/problem/P1307 ...

  7. 2008年NOIP普及组复赛题解

    题目涉及算法: ISBN号码:简单字符串模拟: 排座椅:贪心: 传球游戏:动态规划: 立体图:模拟. ISBN号码 题目链接:https://www.luogu.org/problem/P1055 简 ...

  8. 2005年NOIP普及组复赛题解

    题目涉及算法: 陶陶摘苹果:入门题: 校门外的树:简单模拟: 采药:01背包: 循环:模拟.高精度. 陶陶摘苹果 题目链接:https://www.luogu.org/problem/P1046 循环 ...

  9. 2018年NOIP普及组复赛题解

    题目涉及算法: 标题统计:字符串入门题: 龙虎斗:数学题: 摆渡车:动态规划: 对称二叉树:搜索. 标题统计 题目链接:https://www.luogu.org/problem/P5015 这道题目 ...

随机推荐

  1. 交互题(apio2016Gap)

    题目链接   //Serene #include<algorithm> #include<iostream> #include<cstring> #include& ...

  2. CSS3渐变效果

    一.线性渐变linear-gradient  1.使用方法: background:-webkit-linear-gradient(red,blue);background:-moz-linear-g ...

  3. 忘记用了delete释放内存,如何防止内存溢出

    C++的内存管理还是要自己来做的,自己要进行内存的申请和释放 程序直接kill掉,OS会回收的 但是面试要问到这个问题,其实是想问你别的 RAII,也称为“资源获取就是初始化”,是c++等编程语言常用 ...

  4. Precision和Recall

    学习自: http://blog.csdn.net/wangran51/article/details/7579100

  5. 【JZOJ4855】【NOIP2016提高A组集训第6场11.3】荷花池塘

    题目描述 于大夫建造了一个美丽的池塘,用来让自己愉快的玩耍.这个长方形的池子被分割成了M 行 和N 列的正方形格子.池塘中有些地方是可以跳上的荷叶,有些地方是不能放置荷叶也不 能跳上的岩石,其他地方是 ...

  6. 【JZOJ1611】Dining

    题目描述 农夫JOHN为牛们做了很好的食品,但是牛吃饭很挑食.每一头牛只喜欢吃一些食品和饮料而别的一概不吃.虽然他不一定能把所有牛喂饱,他还是想让尽可能多的牛吃到他们喜欢的食品和饮料. 农夫JOHN做 ...

  7. HDU - 4725_The Shortest Path in Nya Graph

    The Shortest Path in Nya Graph Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (J ...

  8. Libevent:0异步IO简介

    一:异步IO简介 大多数的初级编程者都是从阻塞IO调用开始网络编程的.阻塞(同步)IO调用指的是:调用会一直阻塞,不会返回,直到发生下面两种情况之一.要么操作完成,要么经历相当长的时间,网络协议栈自己 ...

  9. Win10系统使用Docker安装oracle并通过Navicat for oracle进行登录

    一.安装Docker Linux系统可以直接采用命令进行Docker安装: Win7系统安装Dokcer实际通过Boot2Docker在Windows下安装一个VirtualBox来实现: Boot2 ...

  10. Atcoder Tenka1 Programmer Contest D: IntegerotS 【思维题,位运算】

    http://tenka1-2017.contest.atcoder.jp/tasks/tenka1_2017_d 给定N,K和A1...AN,B1...BN,选取若干个Ai使它们的或运算值小于等于K ...