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提高组解题报告的更多相关文章

  1. noip2015 提高组 解题报告

    完美退役...说好的不卡常呢QAQ day1: T1:模拟题?..考察选手将题目描述翻译成代码的能力233 //其实真相是考验rp..论代码雷同的危害233 T2:简单图论,每个点出度为1所以是基环内 ...

  2. NOIP2016提高组解题报告

    NOIP2016提高组解题报告 更正:NOIP day1 T2天天爱跑步 解题思路见代码. NOIP2016代码整合

  3. noip2009提高组解题报告

    NOIP2009潜伏者 题目描述 R 国和S 国正陷入战火之中,双方都互派间谍,潜入对方内部,伺机行动. 历尽艰险后,潜伏于 S 国的R 国间谍小C 终于摸清了S 国军用密码的编码规则: 1. S 国 ...

  4. 2010noip提高组解题报告

    https://www.luogu.org/problem/show?pid=1514 题目描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个 ...

  5. 洛谷 P2678 & [NOIP2015提高组] 跳石头

    题目链接 https://www.luogu.org/problemnew/show/P2678 题目背景 一年一度的“跳石头”比赛又要开始了! 题目描述 这项比赛将在一条笔直的河道中进行,河道中分布 ...

  6. [NOIP2015] 提高组 洛谷P2615 神奇的幻方

    题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. ...

  7. 洛谷-神奇的幻方-NOIP2015提高组复赛

    题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,--,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. ...

  8. 【数据结构】运输计划 NOIP2015提高组D2T3

    [数据结构]运输计划 NOIP2015提高组D2T3 >>>>题目 [题目描述] 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航 ...

  9. 【二分查找】 跳石头NOIP2015提高组 D2T1

    [二分查找]跳石头NOIP2015提高组 D2T1 >>>>题目 [题目描述] 一年一度的“跳石头”比赛又要开始了! 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石 ...

随机推荐

  1. lambda表达式的应用例子和JavaSE 8特性

    在JavaSE 8 引入了lambda表达式,lambda表达式的引入带来的好处是:通过语法上的改进,减少开发人员需要编写和维护的代码数量.这个在下面使用和不使用lambda的对比中可以清晰看出来. ...

  2. static变量与context泄漏

    1.mContext--- public class LoginActivity extends BaseActivity { ....      /**初始化信息*/      private vo ...

  3. 发福利喽稀疏FFT

    附介绍: 四位来自麻省理工学院的研究人员蒂娜·卡塔比(Dina Katabi).海塞姆·哈桑(Haitham Hassanieh).比欧特·因迪克(Piotr Indyk)和埃里克·普里斯(Eric ...

  4. R、Python、Scala和Java,到底该使用哪一种大数据编程语言?

    有一个大数据项目,你知道问题领域(problem domain),也知道使用什么基础设施,甚至可能已决定使用哪种框架来处理所有这些数据,但是有一个决定迟迟未能做出:我该选择哪种语言?(或者可能更有针对 ...

  5. MSSQL数据库 事务隔离级别

    数据库事务的隔离级别有4个,由低到高依次为Read uncommitted .Read committed .Repeatable read .Serializable ,这四个级别可以逐个解 脏读 ...

  6. (Git 钩子)自定义你的工作流 和引用日志

    Git 钩子是在 Git 仓库中特定事件发生时自动运行的脚本.它可以让你自定义 Git 内部的行为,在开发周期中的关键点触发自定义的行为. Git 钩子最常见的使用场景包括推行提交规范,根据仓库状态改 ...

  7. 从零开始PHP攻略(000)——关于WAMPServer集成环境

    Apache.PHP和MySQL都可以用于多种操作系统和Web服务器的组合.本篇介绍在Windows下用WampServer环境包来搭建本地php环境. W:windows A:Apache M:My ...

  8. 【Python学习】Jupyter解决单个变量输出问题

    使用Jupyter的时候有时候发现,我明明写了好几个变量打印,但是它只显示最后一个.Out只有一个. 但是使用下面的语句.就可以实现多个输出. from IPython.core.interactiv ...

  9. telnet如何保存输出内容到本地

    telnet如何保存输出内容到本地 http://bbs.csdn.net/topics/391023327 一种将程序的标准输出重定向到telnet终端的方法 http://blog.chinaun ...

  10. 2.C 基础

    C 基础 原文地址:http://rypress.com/tutorials/objective-c/c-basics OC 可以说是C语言的一个超集,这样你可以无缝的和C语言结合编程也就是你可以这两 ...