博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Noip 模拟练习3
阅读量:4661 次
发布时间:2019-06-09

本文共 6048 字,大约阅读时间需要 20 分钟。

Noip 模拟练习3

  • 满分300,本人100,修正后300
  • 较易

题目:

  • 有图,转

题解:

  • 其实这就是一个简单的卡特兰数。
  • 吐槽,这是原题
  • 证明过程转我写过的一篇
#include 
#include
using namespace std;int n;int dp[25];int main(){ cin >> n; dp[0] = dp[1] = 1; for(int i = 2; i <= n; i++) for(int j = 0; j < i; j++) dp[i] += dp[j] * dp[i - j - 1]; cout << dp[n]; return 0;}

报名查询

Description

  • 某市中考科目繁多,且记分方法特别,以至于总分最高可达 10的6次方。为了公平起见,教育局规定成绩公布后两天为报名时间,考生可以根据自己的成绩选择填报某所学校。

    报名截止后,各校会将填报本校学生的分数从高到低排列,然后按招生计划指定的人数进行

    录取,因此如果志愿填报不合理你就可能落选。为了方便考生及时了解报名情况,该市最牛

    的 110 中学请你开发一个报名辅助软件,该软件主要有四个操作:

    (1) 投档:操作符为“I”,用以处理某位考生报考本校;

    (2) 查询:操作符为“C”,用以处理某位考生查询当前有多少考生总分比自己高;

    (3) 退档:操作符为“D”,用以处理某位考生退出报考本校;

    (4) 截止:操作符为“E”,表示报名截止,软件停止工作。

    在前三个操作中,每个操作符后都会跟有一个分数,操作符和分数之间用一个空格分开。

    如“I 10000”,表示有一名总分是 10000 的考生报考本校;“C 10000”表示当前有一名总分

    是 10000 的考生进行查询,此时程序应返回当前报考本校的考生中有多少个总分超过 10000;

    “D 10000”表示有一名总分是 10000 的考生退出报考本校。

    你的程序应该对每个投档和退档的操作对考生数据库进行实时更新,对每个查询操作输

    出正确的解答。

Input

  • 输入文件 query.in 每行给出一个操作,最后一行是操作符“E”表示输入结束。

    输入中每个操作符“I”、“C”、“D”后都跟有一个不超过 10的6次方

    的正整数,表示参与该次操作

    的考生总分。所有操作的总数不超过 10的6次方

Output

  • 对于输入文件中的每个查询操作“C”,必须在输出文件中给出正确的回答。

Sample Input

I 10000

I 20000

C 20000

I 10000

C 10000

I 5000

D 10000

C 5000

E

Sample output

0

1

2

题解:

  • 线段树 + 离散化
  • 复杂度是可以接受的,如果树的深度是21亿,找一个结点只需30几下。所以logn的复杂度是十分优秀的。何况这里的数据最大才10的6次方。
  • 区间修改 + 单点查询
  • 如果有一个分数为x的学生投档,那么比x低的分数那一段区间+1。退档即-1。
  • 查询直接查询那个分数位置即可。
  • 坑点:查询的成绩可能在之前并没有出现过而且大小随机
#include 
#include
#include
#include
#define maxn 1000005using namespace std;struct Tree {int l, r, val, tag;}tree[maxn * 4];struct A {int op, num;} a[maxn];int n, cnt;int b[maxn];int read(){ int x = 0; char c = getchar(); while(c < '0' || c > '9') c = getchar(); while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();} return x;}int find(int x) { return upper_bound(b + 1, b + 1 + cnt, x) - b - 1; //注意查询的元素是不一定出现且随机的}void build(int root, int l, int r){ tree[root].l = l, tree[root].r = r; if(l == r) return; int mid = (l + r) >> 1; build(root << 1, l, mid); build(root << 1 | 1, mid + 1, r);}void down(int root){ int son1 = root << 1, son2 = root << 1 | 1; tree[son1].tag += tree[root].tag, tree[son2].tag += tree[root].tag; tree[son1].val += (tree[son1].r - tree[son1].l + 1) * tree[root].tag; tree[son2].val += (tree[son2].r - tree[son2].l + 1) * tree[root].tag; tree[root].tag = 0;}void update(int root, int l, int r, int add){ if(tree[root].l >= l && tree[root].r <= r) { tree[root].tag += add; tree[root].val += (tree[root].r - tree[root].l + 1) * add; return; } if(tree[root].tag) down(root); int mid = (tree[root].l + tree[root].r) >> 1; if(l <= mid) update(root << 1, l, r, add); if(r > mid) update(root << 1 | 1, l, r, add); tree[root].val = tree[root << 1].val + tree[root << 1 | 1].val;}int ask(int root, int l, int r){ if(tree[root].l >= l && tree[root].r <= r) return tree[root].val; if(tree[root].tag) down(root); int mid = (tree[root].l + tree[root].r) >> 1, ans = 0; if(l <= mid) ans += ask(root << 1, l, r); if(r > mid) ans += ask(root << 1 | 1, l, r); return ans;}int main(){ while(1) { char c = getchar(); if(c == 'E') break; int num = read(); a[++n].num = num; if(c == 'I') b[++cnt] = num, a[n].op = 1; else if(c == 'C') a[n].op = 2; else if(c == 'D') a[n].op = 3; } b[++cnt] = 0; //细节!为了求出比最差成绩高的成绩个数 sort(b + 1, b + 1 + cnt); cnt = unique(b + 1, b + 1 + cnt) - b - 1; build(1, 1, cnt); for(int i = 1; i <= n; i++) { if(a[i].op == 1 && find(a[i].num) - 1 >= 1) update(1, 1, find(a[i].num) - 1, 1); else if(a[i].op == 3 && find(a[i].num) - 1 >= 1) update(1, 1, find(a[i].num) - 1, -1); else if(a[i].op == 2) { if(find(a[i].num) > cnt) printf("0\n"); else printf("%d\n", ask(1, find(a[i].num), find(a[i].num))); } } return 0;}

方格取数

Description

  • 为了使漫长的星际旅行变得更加有趣,航天员发明了一种益智游戏:一个由 NN个格子组成的棋盘上,填上 N N个标有数字的棋子,并给定一个整数 M,若相邻两个格子 (即有公共边的格子)中的棋子所标的数字之差的绝对值不超过 M,则可以将这两个棋子从棋 盘中拿去,游戏的目标是使剩下的棋子最少。 你的任务是写一个程序,对于一个初始棋盘和给定的 M 值,求出剩余棋子最少的取子方案。

Input

  • 输入文件 fgqs.in 的第一行给出 N 和 M 的值,这两个数之间用一个空格分开,其

    中 1≤N,M≤100。20%的数据 1≤N,M≤10。

    以下 N 行,每行有 N 个正整数,给出初始棋盘每个格子中棋子上所标的数,该数不超过

    1000,同一行相邻两个整数之间用一个空格分开。

Output

  • 输出文件 fgqs.out 仅有一个整数,即你得到的最佳取子方案中剩下的棋子数。

Sample Input

3 2

3 2 5

7 1 2

3 6 9

Sample Output

5

题解:

  • 思路1:搜索。

    • 考场上我就是这么做的。做的好的话20分。可是我爆掉了
  • 思路2:联通块

    • 第一次修正时是这样做的。即用搜索找出一个个互相间有关系的联通块。对于每个联通块,它所产生的贡献就是(int)(块里元素个数 / 2) * 2。最后ans就等于n * n - 所以块的贡献
    • 这样乍一看没有错误。但其实有个长这样的联通块:

    0

    0

    0

    0 0

    0

    • 按理说这个块的贡献是3。但你手玩就会发现贡献是2
  • 思路3:二分图匹配

    • 看来我对二分图还是不够敏感啊,这是老师讲的正解
    • 只要看到“两个东西匹配”这种字眼或者有这种感觉的题目,一定要联想到二分图
    • 跟以往不同的是,不用把图分成两部分,每个点都尝试匹配。不把图分成两部分的话就需要要更新mat时互相的mat都要更新
    • 这题也告诉了我们二分图匹配不一定一定要把图分成两部分
    • 你可能会问:怎么证明它时一个二分图?
    • 证明如下:

    ZhSheP.png

#include 
#include
#include
#include
#define maxn 105using namespace std;struct Mat {int x, y;} mat[maxn][maxn];int n, m, tot;int a[maxn][maxn];int dx[5] = {0, -1, 1, 0, 0};int dy[5] = {0, 0, 0, -1, 1};bool vis[maxn][maxn];bool dfs(int x, int y){ for(int i = 1; i <= 4; i++) { int xx = x + dx[i], yy = y + dy[i]; if(xx >= 1 && xx <= n && yy >= 1 && yy <= n) if(abs(a[x][y] - a[xx][yy]) <= m && !vis[xx][yy]) { vis[xx][yy] = 1; if(!mat[xx][yy].x || dfs(mat[xx][yy].x, mat[xx][yy].y)) { mat[xx][yy].x = x, mat[xx][yy].y = y; mat[x][y].x = xx, mat[x][y].y = yy; return 1; } } } return 0;}int main(){ cin >> n >> m; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) cin >> a[i][j]; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) if(!mat[i][j].x && dfs(i, j)) { tot++; memset(vis, 0, sizeof(vis)); } cout << n * n - 2 * tot; return 0;}

转载于:https://www.cnblogs.com/BigYellowDog/p/11178658.html

你可能感兴趣的文章
DP(动态规划)
查看>>
chkconfig
查看>>
2.抽取代码(BaseActivity)
查看>>
夏天过去了, 姥爷推荐几套来自smashingmagzine的超棒秋天主题壁纸
查看>>
反射的所有api
查看>>
css 定位及遮罩层小技巧
查看>>
[2017.02.23] Java8 函数式编程
查看>>
sprintf 和strcpy 的差别
查看>>
JS中window.event事件使用详解
查看>>
ES6深入学习记录(一)class方法相关
查看>>
C语言对mysql数据库的操作
查看>>
INNO SETUP 获得命令行参数
查看>>
docker安装部署
查看>>
AVL树、splay树(伸展树)和红黑树比较
查看>>
多媒体音量条显示异常跳动
查看>>
运算符及题目(2017.1.8)
查看>>
ssh自动分发密匙脚本样板
查看>>
转 小辉_Ray CORS(跨域资源共享)
查看>>
Linux安装postgresql
查看>>
MyBatis启动:MapperStatement创建
查看>>