Noip2015提高组解题报告
Day1
T1神奇的幻方
一道简单异常的小模拟,我们只需要确定数字1的位置,然后根据题意枚举即可,简简单单就A了,什么也不卡。
然而这题,我刚开始学OI的时候,因为当时比较蠢,被这题花式吊打啊....根本不会啊.....
ε=(´ο`*)))唉又想起没学OI的自己了..
虽然题简单,还是惯例丢代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = ;
int a[maxn][maxn];
int n, x, y; inline int read() {
int x = , y = ;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') y = -;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << ) + (x << ) + ch - '';
ch = getchar();
}
return x * y;
} int main() {
n = read();
x = , y = n / + ;
a[x][y] = ;
for(register int i = ; i <= n * n; ++i) {
if(x == && y != n) {
x = n, y += ;
a[x][y] = i;
}
else if(x != && y == n) {
x -= , y = ;
a[x][y] = i;
}
else if(x == && y == n) {
x += ;
a[x][y] = i;
}
else if(x != && y != n) {
if(!a[x - ][y + ]) {
x -= , y += ;
a[x][y] = i;
}
else if(a[x - ][y + ]) {
x += ;
a[x][y] = i;
}
}
}
for(register int i = ; i <= n; ++i) {
for(register int j = ; j <= n; ++j)
printf("%d ", a[i][j]);
printf("\n");
}
return ;
}
T2信息传递
大意就是说一堆人会一直传话,形成一个环,问你最小的环里有多少个人
显然你可以直接tarjan跑强联通分量,当然你也可以跑并查集等做法做
并查集写法简单讲就是在路径压缩同时维护环的大小,对于给出的传递者与被传递者,判断是不是一个集合里的,不是就合并
是就更新答案
#include<bits/stdc++.h>
#define ll long long
#define uint unsigned int
#define ull unsigned long long
using namespace std;
const int maxn = ;
const int inf = ;
int t, fa[maxn];
int dis[maxn], ans;
int n; inline int read() {
int x = , y = ;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') y = -;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << ) + (x << ) + ch - '';
ch = getchar();
}
return x * y;
} int getfather(int x) {
if(x == fa[x]) return x;
int son_in_son = fa[x];
fa[x] = getfather(fa[x]);
dis[x] += dis[son_in_son];
return fa[x];
} int main() {
// freopen("message.in", "r", stdin);
// freopen("message.out", "w", stdout);
n = read();
for(register int i = ; i <= n; ++i) fa[i] = i;
ans = inf;
for(register int i = ; i <= n; ++i) {
t = read();
int u = getfather(i), v = getfather(t);
if(u != v) {
fa[u] = v;
dis[i] = dis[t] + ;
}
else ans = min(ans, dis[i] + dis[t] + );
}
printf("%d\n", ans);
return ;
}
tarjan就更简单了,跑强连通分量,统计每个环中节点的大小,然后找最小的大小不为1环的就好了
#include<bits/stdc++.h>
#define ll long long
#define uint unsigned int
#define ull unsigned long long
using namespace std;
const int maxn = ;
const int inf = ;
struct shiki {
int net, y;
}e[maxn << ];
int lin[maxn], len = ;
int dfn[maxn], low[maxn];
int num = , cnt = , top = ;
int c_num[maxn], s[maxn];
bool in_s[maxn];
int sum[maxn];
int n, t, ans; inline int read() {
int x = , y = ;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') y = ;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << ) + (x << ) + ch - '';
ch = getchar();
}
return x * y;
} inline void insert(int xx, int yy) {
e[++len].y = yy;
e[len].net = lin[xx];
lin[xx] = len;
} void tarjan(int x) {
dfn[x] = low[x] = ++num;
s[++top] = x, in_s[x] = ;
for(int i = lin[x]; i; i = e[i].net) {
int to = e[i].y;
if(!dfn[to]) {
tarjan(to);
low[x] = min(low[x], low[to]); }
else if(in_s[to]) low[x] = min(low[x], dfn[to]);
}
if(dfn[x] == low[x]) {
cnt++; int k;
do {
k = s[top--], in_s[k] = ;
c_num[k] = cnt;
}while(x != k);
}
} int main() {
memset(sum, , sizeof(sum));
n = read();
for(register int i = ; i <= n; ++i) {
t = read();
insert(i, t);
}
for(register int i = ; i <= n; ++i)
if(!dfn[i]) tarjan(i);
for(register int i = ; i <= n; ++i)
sum[c_num[i]]++;
ans = inf;
for(register int i = ; i <= cnt; ++i)
if(sum[i] != ) ans = min(ans, sum[i]);
printf("%d\n", (ans != inf) ? ans : );
return ;
}
T3斗地主
这题当年显然恶心的不少的人
这题确实比较恶心,尤其是那诡异的一堆牌的出法,因为和真实斗地主不一样,比较不适
对于这点,我们本着:“所有题面没说是不合法的情况,都是合法的” 的原则,可以知道最烦人的大小王,他们不是对,他们是单牌,所以炸弹带大小王是合法的!
因为炸弹可以带两张单牌。
我们贪心的想一想,显然我们要想出牌次数最小,一定是要尽可能的先把所有能一次丢走顺子和带牌都出完,最后剩下的牌在甩完就好,所以我们可以爆搜顺子和带牌加上最后剩下的牌的出牌次数,答案求min
好吧和贪心并没有什么关系,我们做这题首先要有一个合理的搜索顺序:先搜顺子和带牌,最后处理剩余的牌
因为显然,除了顺子,带牌,剩下的无论是什么都可以一次出完,而相比枚举出掉什么单牌或对子或炸弹
显然顺子和带牌的情况更方便处理,这样我们就可以爆搜了,奥对,顺子和带牌先搜哪个后搜哪个都是可以A题的
#include<bits/stdc++.h>
using namespace std;
const int maxn = ;
const int inf = ;
int sum[maxn];
int T, n, ans; inline int read() {
int x = , y = ;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') y = -;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << ) + (x << ) + ch - '';
ch = getchar();
}
return x * y;
} void dfs_kill(int x) {//出牌次数
/*
可以公开的情报:
出牌方式有火箭,炸弹,单牌,对牌,三不带,三带单,三带对,
顺子,连对,三顺, 四带二(且带的两张牌不要求相同)
*/
if(x >= ans) return;
//顺子势力
int op = ;//单顺
for(register int i = ; i <= ; ++i) {//2与双王不可用
if(sum[i] < ) op = ;//打断顺子
else {
op++;//长度加1
if(op >= ) {
for(register int j = i - op + ; j <= i; ++j) sum[j]--;//出牌
dfs_kill(x + );
for(register int j = i - op + ; j <= i; ++j) sum[j]++;//回溯
}
}
}
op = ;//连对
for(register int i = ; i <= ; ++i) {
if(sum[i] < ) op = ;//打断连对
else {
op++;
if(op >= ) {
for(register int j = i - op + ; j <= i; ++j) sum[j] -= ;
dfs_kill(x + );
for(register int j = i - op + ; j <= i; ++j) sum[j] += ;
}
}
}
op = ;//三顺
for(register int i = ; i <= ; ++i) {
if(sum[i] < ) op = ;
else {
op++;
if(op >= ) {
for(register int j = i - op + ; j <= i; ++j) sum[j] -= ;
dfs_kill(x + );
for(register int j = i - op + ; j <= i; ++j) sum[j] += ;
}
}
}
//带牌
for(register int i = ; i <= ; ++i) {//大小王不能带牌
if(sum[i] < ) continue;//连三带都不行的
sum[i] -= ;//大家都先搞三带
for(register int j = ; j <= ; ++j) {//三带一居然能带大小王??
if(sum[j] < || j == i) continue;
sum[j]--;
dfs_kill(x + );
sum[j]++;
}
for(register int j = ; j <= ; ++j) {//三带二,大小王不算对子
if(sum[j] < || j == i) continue;
sum[j] -= ;
dfs_kill(x + );
sum[j] += ;
}
sum[i] += ;
if(sum[i] > ) {//一些群众可以四带
sum[i] -= ;
for(register int j = ; j <= ; ++j) {//带单牌之时,大小王算单牌
if(sum[j] < || j == i) continue;
sum[j]--;
for(register int k = ; k <= ; ++k) {
if(sum[k] < || (k == j && k != ) || k == i) continue;
sum[k]--;
dfs_kill(x + );
sum[k]++;
}
sum[j]++;
}
for(register int j = ; j <= ; ++j) {//带双牌之时,大小王不算对子
if(sum[j] < || j == i) continue;
sum[j] -= ;
for(register int k = ; k <= ; ++k) {
if(sum[k] < || k == j || k == i) continue;
sum[k] -= ;
dfs_kill(x + );
sum[k] += ;
}
sum[j] += ;
}
sum[i] += ;
}
}
//已经处理完了顺子,连对,三顺,三带一,三带二,四带二单,四带二对
//对于剩下的势力,显然可以一次性丢出去
for(register int i = ; i <= ; ++i) if(sum[i]) x++;
ans = min(ans, x);
} int main() {
// freopen("landlords.in", "r", stdin);
// freopen("landlords.out", "w", stdout);
T = read(), n = read();
while(T--) {
memset(sum, , sizeof(sum));
ans = inf;
for(register int i = ; i <= n; ++i) {
int which = read(), col = read();
if(which == ) sum[]++;//大小王放在同一个位置
else if(which == ) sum[]++;//塞进一个A,因为A可以丢进顺子等组合且比较大,放在后面
else sum[which]++;
}
dfs_kill();
printf("%d\n", ans);
}
return ;
}
这样我们就把Noip2015Day1给AK了,实际上就这套题的难度来看,前两题简直是送分,我写前两题甚至没超过半个小时(大概?)
最后T3确定好规则和搜索顺序,因为数据随机,所以直接爆搜并不难过。这样,你就有个极大的优势了
Day2
跳石头
挺经典的二分答案题目(不)
二分一个距离,然后开始判定是否合法:
定义一个变量now表示现在在哪块石头上,ans表示能拿掉的石头数量
若枚举到的石头i与now的距离小于二分出的距离,将ans++;
否则令now = i;
若最后ans <= m,则距离不够(显然会有人想知道为什么ans==m不行,我们想一下,我们能够跳到一块石头为i+m,那么按照我们的判定方式,就将i+m拿掉了,然而我们能不能跳到第i+m+1块石头呢?因为必然要有一块岩石做终点,不能跳到水里,所以我们至少要能够拿掉m+1块石头才能说明我们一定能拿掉m块石头并且保证有起点和终点)
#include<bits/stdc++.h>
using namespace std;
const int maxn = ;
int a[maxn];
int L, m, n; inline int read() {
int x = , y = ;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') y = -;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << ) + (x << ) + ch - '';
ch = getchar();
}
return x * y;
} inline bool check(int x) {
int ans = , now = ;
for(int i = ; i <= n; ++i)
if(a[i] - now < x) ans++;
else now = a[i];
return ans <= m;
} int main() {
L = read(), n = read(), m = read();
for(int i = ; i <= n; ++i) a[i] = read();
int l = , r = L;
while(l < r) {
int mid = l + r >> ;
if(check(mid)) l = mid + ;
else r = mid - ;
}
if(!check(l)) l -= ;
printf("%d\n", l);
return ;
}
子串
这题,还挺好写的....
高端做法不会,但是我们可以很容易的想到一个四维的状态
f[i, j, k, 0/1]表示A串取到了第i个字符,B串匹配了j个字符,使用了k个子串,第i个字符取或是不取
方程:
f[i][j][k][0] = (f[i-1][j][k][0] + f[i-1][j][k][1]) % mod
如果ai != bj 则 f[i][j][k][1] = 0
否则 f[i][j][k][1] = (f[i-1][j - 1][k][1] + (f[i-1][j - 1][k - 1][0] + f[i-1][j - 1][k - 1][1]
因为空间问题(毕竟是四维嘛...)我们使用滚动数组即可
初态:f[0][0][0][0] = f[1][0][0][0] = 1
末态:f[n][m][k][0]+f[n][m][k][1]
然后就简简单单地A题了
#include<bits/stdc++.h>
using namespace std;
const int mod = ;
const int maxn = ;
const int maxm = ;
int f[][maxm][maxm][];
char a[maxn], b[maxm];
int n, m, l, id = ; inline int read() {
int x = , y = ;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') y = -;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << ) + (x << ) + ch - '';
ch = getchar();
}
return x * y;
} int main() {
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
n = read(), m = read(), l = read();
scanf("%s%s", a + , b + );
f[][][][] = f[][][][] = ;
for(register int i = ; i <= n; ++i) {
for(register int j = ; j <= m; ++j)
for(register int k = ; k <= l; ++k) {
f[i&][j][k][] = (f[(i-)&][j][k][] + f[(i-)&][j][k][]) % mod;
if(a[i] != b[j]) f[i&][j][k][] = ;
else f[i&][j][k][] = (f[(i-)&][j - ][k][] + (f[(i-)&][j - ][k - ][] + f[(i-)&][j - ][k - ][]) % mod) % mod;
}
}
printf("%d\n", (f[n & ][m][l][] + f[n & ][m][l][]) % mod);
return ;
}
运输计划
两天来最难的题,当然对于一些大佬,这题比斗地主简单
题解:LCA+差分+二分
先咕咕咕一下回头一定补咕咕咕咕
Noip2015提高组解题报告的更多相关文章
- noip2015 提高组 解题报告
完美退役...说好的不卡常呢QAQ day1: T1:模拟题?..考察选手将题目描述翻译成代码的能力233 //其实真相是考验rp..论代码雷同的危害233 T2:简单图论,每个点出度为1所以是基环内 ...
- NOIP2016提高组解题报告
NOIP2016提高组解题报告 更正:NOIP day1 T2天天爱跑步 解题思路见代码. NOIP2016代码整合
- noip2009提高组解题报告
NOIP2009潜伏者 题目描述 R 国和S 国正陷入战火之中,双方都互派间谍,潜入对方内部,伺机行动. 历尽艰险后,潜伏于 S 国的R 国间谍小C 终于摸清了S 国军用密码的编码规则: 1. S 国 ...
- 2010noip提高组解题报告
https://www.luogu.org/problem/show?pid=1514 题目描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个 ...
- 洛谷 P2678 & [NOIP2015提高组] 跳石头
题目链接 https://www.luogu.org/problemnew/show/P2678 题目背景 一年一度的“跳石头”比赛又要开始了! 题目描述 这项比赛将在一条笔直的河道中进行,河道中分布 ...
- [NOIP2015] 提高组 洛谷P2615 神奇的幻方
题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. ...
- 洛谷-神奇的幻方-NOIP2015提高组复赛
题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,--,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. ...
- 【数据结构】运输计划 NOIP2015提高组D2T3
[数据结构]运输计划 NOIP2015提高组D2T3 >>>>题目 [题目描述] 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航 ...
- 【二分查找】 跳石头NOIP2015提高组 D2T1
[二分查找]跳石头NOIP2015提高组 D2T1 >>>>题目 [题目描述] 一年一度的“跳石头”比赛又要开始了! 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石 ...
随机推荐
- 基于html5的动画库,非svg和canvas
基于html5的动画库,非svg和canvas https://greensock.com/docs/#/HTML5/GSAP/TweenLite/
- Item 8 覆盖equals时请遵守通用约定
在覆盖equals方法的时候,你必须要遵守它的通用约定,不遵守,写出来的方法,会出现逻辑错误.下面是约定的内容: equals方法实现了等价关系: 自反性.对于任何非null的引用值,x.eq ...
- 【BZOJ】4558: [JLoi2016]方
[题意]给定有(n+1)*(m+1)个点的网格图,其中指定k个点不合法,求合法的正方形个数(四顶点合法). [算法]计数 [题解]斜着的正方形很麻烦,所以考虑每个斜正方形其外一定有正的外接正方形. 也 ...
- 数据分析之CE找数据大法
一.基本介绍 CE的全称为Cheat Engine,是一款内存修改编辑工具,其官网是http://www.cheatengine.org,可以在其官网下载到最新的CE工具,目前最新版本是Cheat E ...
- 大聊Python----Select解析
1.首先列一下,sellect.poll.epoll三者的区别 select select最早于1983年出现在4.2BSD中,它通过一个select()系统调用来监视多个文件描述符的数组,当sele ...
- js_同步和异步
刚开始写js那会,对这一块是知之甚少,太多太多的知识不足,致使做什么都很艰难.现在工作也有段时间了,知识也有了点积累, 写点什么分享一下. 同步和异步?这个问题是在使用ajax请求后台数据的时候出现的 ...
- Linux System.map文件【转】
转自:http://blog.csdn.net/ysbj123/article/details/51233618 当运行GNU链接器gld(ld)时若使用了"-M"选项,或者使用n ...
- python基础===利用PyCharm进行Python远程调试(转)
原文链接:利用PyCharm进行Python远程调试 背景描述 有时候Python应用的代码在本地开发环境运行十分正常,但是放到线上以后却出现了莫名其妙的异常,经过再三排查以后还是找不到问题原因,于是 ...
- python3使用web.py遇到的找不属性的错误解决
今天用pyhon安装完web.py的时候,点击运行还是没错的,但是在网页输入链接就会报错.1.安装我是这样的: pip install web.py 2.运行后错误信息是这样: AttributeEr ...
- linux命令(10):ps命令
1.查看mysql进程数: ps -ef | grep "mysql" | grep -v "grep" | wc –l 2.监控CPU状态:ps –au 3. ...