*注意:这套题目题面请在loj / uoj查看

Problem A 小 Y 和地铁

题目传送门

  传送点L

  传送点U

题目大意

  小Y乘坐0号地铁线路。城市中有不超过$n + 1$条地铁线路。地铁线路不会自交,两条不同的地铁线路最多有两个交点,交点处一定是换乘站,同时也没有三条地铁线路交于一点。小Y经过了$n$个换乘站,依次给通过它们能过换到的另一条地铁线路的编号,问城市中之多还有多少个换乘站。

  显然只与0号地铁相交1次的地铁线路没有用。

  下面的点指的是一个换乘站,它的颜色编号指的是它能够换乘的另一条地铁的编号。

  然后认真画图可以发现,连接两个颜色相同的点,实际上会将整个图划分成两个区域,所以总共有四种不同的连线方法:

  于是有了$2^{45}\times 45$的优秀做法。

  我们考虑从小到达考虑每种颜色的第一个点,我们发现按照对后面的贡献可以将决策分为两种:

  每一行的两种状态对后面的影响是一样的,所以我们可以对每一行的两种决策对当前的影响取最小值继续进行搜索。

  这样时间复杂度降为$O(Tn2^{n/2})$。

  加一个最优性剪枝即可通过。

Code

 /**
* loj
* Problem#2323
* Accepted
* Time: 3349ms
* Memory: 252k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; const int N = ; int T;
int n;
int ar[N], br[N], hs[N];
int cup, cdn;
int ups[N], dns[N]; inline void init() {
scanf("%d", &n);
memset(hs, , sizeof(hs));
memset(ar, , sizeof(ar));
for (int i = ; i <= n; i++) {
scanf("%d", br + i);
ar[hs[br[i]]] = i, hs[br[i]] = i;
}
} int res;
void dfs(int p, int cur) {
if (cur >= res)
return ;
if (p > n) {
res = cur;
return ;
}
if (!ar[p])
dfs(p + , cur);
else {
int cnt1 = , cnt2 = ;
for (int i = ; i < cup; i++) {
cnt1 += (ups[i] > p && ups[i] < ar[p]);
cnt2 += (ups[i] > ar[p]);
}
for (int i = ; i < cdn; i++)
cnt2 += (dns[i] > p);
ups[cup++] = ar[p];
dfs(p + , cur + min(cnt1, cnt2)); cup--, cnt1 = , cnt2 = ;
for (int i = ; i < cdn; i++) {
cnt1 += (dns[i] > p && dns[i] < ar[p]);
cnt2 += (dns[i] > ar[p]);
}
for (int i = ; i < cup; i++)
cnt2 += (ups[i] > p);
dns[cdn++] = ar[p];
dfs(p + , cur + min(cnt1, cnt2));
cdn--;
}
} inline void solve() {
res = ;
dfs(, );
printf("%d\n", res);
} int main() {
scanf("%d", &T);
while (T--) {
init();
solve();
}
return ;
}

Problem A

Problem B 小 Y 和二叉树

题目传送门

  传送点L

  传送点U

题目大意

  给定一个无根二叉树,要求定根并指定左右子树,使得中序遍历字典序最小。输出最小字典序中序遍历

  显然度数小于3的最小的点是中序遍历的第一个点,记它为$R$。(因为可以构造方案)

  当主动进入一个以点$s$为根子树中时,那么第一个点一定是其中标号最小的度数小于3的点,设它的标号为$f_{s}$。

  剩下的就是贪心。首先从$R$开始贪,如果它的度数为2,那么从它的左右子树中选取$f$值较小的作为右子树。

  然后大概就是这样大力分类讨论。

  主动进入子树和跳父亲的讨论是不一样的,所以要写两个dfs。

Code

 /**
* loj
* Problem#2324
* Accepted
* Time: 2486ms
* Memory: 86200k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; typedef class IO {
protected:
const static int Limit = ;
FILE* file; int ss, st;
char buf[Limit];
public:
IO():file(NULL) { };
IO(FILE* file):file(file) { } void open(FILE *file) {
this->file = file;
} char pick() {
if (ss == st)
st = fread(buf, , Limit, file), ss = ;//, cerr << "Str: " << buf << "ED " << st << endl;
return buf[ss++];
}
}IO; #define digit(_x) ((_x) >= '0' && (_x) <= '9') IO& operator >> (IO& in, int& u) {
char x;
while (~(x = in.pick()) && !digit(x));
for (u = x - ''; ~(x = in.pick()) && digit(x); u = u * + x - '');
return in;
} IO in(stdin); const int N = 1e6 + ;
const signed inf = (signed) (~0u >> ); int n;
int rt, tp = ;
int f[N], deg[N];
vector<int> g[N];
int ans[N]; inline void init() {
in >> n;
for (int i = ; i <= n; i++) {
in >> deg[i];
if (deg[i] < && !rt)
rt = i;
for (int j = , x; j < deg[i]; j++) {
in >> x;
g[i].push_back(x);
}
}
} int cnt = ;
void dp(int p, int fa) {
cnt++;
f[p] = ((deg[p] < ) ? (p) : (inf));
for (int i = , e; i < deg[p]; i++)
if ((e = g[p][i]) != fa) {
dp(e, p);
f[p] = min(f[p], f[e]);
}
} #define s1 son[0]
#define s2 son[1] void dfs1(int p, int fa) { // a certain subtree
int son[], top = ;
for (int i = , e; i < deg[p]; i++)
if ((e = g[p][i]) != fa)
son[top++] = e;
if (!top) {
ans[tp++] = p;
} else if (top == ) {
if (p < f[s1])
ans[tp++] = p, dfs1(s1, p);
else
dfs1(s1, p), ans[tp++] = p;
} else {
if (f[s1] < f[s2])
dfs1(s1, p), ans[tp++] = p, dfs1(s2, p);
else
dfs1(s2, p), ans[tp++] = p, dfs1(s1, p);
}
} void dfs2(int p, int fa) { // haven't known which node is root yet
int son[], top = ;
for (int i = , e; i < deg[p]; i++)
if ((e = g[p][i]) != fa)
son[top++] = e;
ans[tp++] = p;
if (!top)
return;
if (top == ) {
if (s1 <= f[s1])
dfs2(s1, p);
else
dfs1(s1, p);
} else {
if (f[s1] < f[s2])
dfs1(s1, p), dfs2(s2, p);
else
dfs1(s2, p), dfs2(s1, p);
}
} inline void solve() {
dp(rt, );
dfs2(rt, );
for (int i = ; i < n; i++)
printf("%d ", ans[i]);
} int main() {
init();
solve();
return ;
}

Problem B

Problem C 小 Y 和恐怖的奴隶主

题目传送门

  传送点L

  传送点U

题目大意

  (原题很简洁)

  直接做期望不好做(就是傻逼想直接算期望,然后发现非常难去掉非法转移),我们考虑计算概率,每次转移的时候更新期望。这样就能把转移化成乘上某个矩阵。

  然后发现多组询问,很GG。我们倍增一下,向量乘矩阵就行了。

  这道题交uoj可能需要优化一下,某larryzhong出极限数据卡人。

  我们来讲讲这道题怎么卡常:

  1. 矩阵不要开结构体。
  2. 矩阵乘法直接写代码乘,不写函数或重载运算符
  3. 矩阵乘法时取大小模数,小模数是题目模数,大模数是在1次乘法中不会爆掉的模数,并且必须是小模数的倍数,然后每次矩阵乘法中的乘直接乘,加变成在大模数意义下加,运算完后再将所有数对小模数取模。
  4. 加的时候加取模优化。
  5. 矩阵乘法时使用恰当的循环顺序改善内存访问。

  然后就可以跑在std前面了。

Code

 /**
* uoj
* Problem#340
* Accepted
* Time: 2267ms
* Memory: 14264k
*/
#include <bits/stdc++.h>
#ifndef WIN32
#define Auto "%lld"
#else
#define Auto "%I64d"
#endif
using namespace std;
typedef bool boolean;
#define ll long long const int M = ;
const ll Mod = 3ll * M * M;
const int bzmax = ; ll Add(ll a, ll b) {
return ((a += b) >= Mod) ? (a - Mod) : (a);
} const int N = ; int qpow(int a, int p) {
if (p < )
p += M - ;
ll rt = , pa = a;
for ( ; p; p >>= , pa = pa * pa % M)
if (p & )
rt = rt * pa % M;
return rt;
} int T;
ll n;
int m, K;
int cS = ;
int id[][][];
ll v1[N], v2[N];
ll *f, *bf;
ll powg[bzmax][N][N]; int addServlant(int x, int y, int z) {
if (x + y + z == K)
return id[x][y][z];
return id[x + (m == )][y + (m == )][z + (m == )];
} inline void init() {
scanf("%d%d%d", &T, &m, &K); for (int i = ; i <= K; i++)
for (int j = ; i + j <= K && (m >= || !j); j++)
for (int k = ; i + j + k <= K && (m == || !k); k++)
id[i][j][k] = cS++;
cS++; ll (*g)[N] = powg[];
for (int i = ; i <= K; i++)
for (int j = ; i + j <= K && (m >= || !j); j++)
for (int k = ; i + j + k <= K && (m == || !k); k++) {
int l = i + j + k + , s = id[i][j][k];
ll invl = qpow(l, -);
if (i)
g[s][id[i - ][j][k]] = invl * i % M;
if (j)
g[s][addServlant(i + , j - , k)] = invl * j % M;
if (k)
g[s][addServlant(i, j + , k - )] = invl * k % M;
g[s][s] = invl, g[s][cS - ] = invl;
}
g[cS - ][cS - ] = ; for (int i = ; i < bzmax; i++) {
ll (*A)[N] = powg[i - ], (*B)[N] = powg[i];
for (int x = ; x < cS; x++)
for (int k = ; k < cS; k++)
for (int y = ; y < cS; y++)
B[x][y] = Add(B[x][y], A[x][k] * A[k][y]);
for (int x = ; x < cS; x++)
for (int y = ; y < cS; y++)
B[x][y] %= M;
}
// powg[i] = powg[i - 1] * powg[i - 1];
} inline void solve() {
f = v1, bf = v2;
while (T--) {
scanf(Auto, &n);
memset(f, , sizeof(ll) * N);
f[id[(m == )][(m == )][(m == )]] = ;
for (int i = ; i < bzmax; i++)
if ((n >> i) & ) {
memset(bf, , sizeof(ll) * N);
for (int x = ; x < cS; x++)
for (int k = ; k < cS; k++)
bf[k] = Add(bf[k], f[x] * powg[i][x][k]);
for (int x = ; x < cS; x++)
bf[x] %= M;
swap(f, bf);
}
printf("%d\n", f[cS - ]);
}
} int main() {
init();
solve();
return ;
}

Problem C

清华集训2017 Day 2简要题解的更多相关文章

  1. 【UOJ#340】【清华集训2017】小 Y 和恐怖的奴隶主(矩阵快速幂,动态规划)

    [UOJ#340][清华集训2017]小 Y 和恐怖的奴隶主(矩阵快速幂,动态规划) 题面 UOJ 洛谷 题解 考虑如何暴力\(dp\). 设\(f[i][a][b][c]\)表示当前到了第\(i\) ...

  2. [LOJ#2330]「清华集训 2017」榕树之心

    [LOJ#2330]「清华集训 2017」榕树之心 试题描述 深秋.冷风吹散了最后一丝夏日的暑气,也吹落了榕树脚下灌木丛的叶子.相识数年的Evan和Lyra再次回到了小时候见面的茂盛榕树之下.小溪依旧 ...

  3. [LOJ#2329]「清华集训 2017」我的生命已如风中残烛

    [LOJ#2329]「清华集训 2017」我的生命已如风中残烛 试题描述 九条可怜是一个贪玩的女孩子. 这天她在一堵墙钉了 \(n\) 个钉子,第 \(i\) 个钉子的坐标是 \((x_i,y_i)\ ...

  4. [LOJ#2328]「清华集训 2017」避难所

    [LOJ#2328]「清华集训 2017」避难所 试题描述 "B君啊,你当年的伙伴都不在北京了,为什么你还在北京呢?" "大概是因为出了一些事故吧,否则这道题就不叫避难所 ...

  5. [LOJ#2327]「清华集训 2017」福若格斯

    [LOJ#2327]「清华集训 2017」福若格斯 试题描述 小d是4xx9小游戏高手. 有一天,小d发现了一个很经典的小游戏:跳青蛙. 游戏在一个 \(5\) 个格子的棋盘上进行.在游戏的一开始,最 ...

  6. [LOJ#2326]「清华集训 2017」简单数据结构

    [LOJ#2326]「清华集训 2017」简单数据结构 试题描述 参加完IOI2018之后就是姚班面试.而你,由于讨厌物理.并且想成为乔布斯一样的创业家,被成功踢回贵系. 转眼,时间的指针被指向201 ...

  7. [LOJ#2324]「清华集训 2017」小Y和二叉树

    [LOJ#2324]「清华集训 2017」小Y和二叉树 试题描述 小Y是一个心灵手巧的OIer,她有许多二叉树模型. 小Y的二叉树模型中,每个结点都具有一个编号,小Y把她最喜欢的一个二叉树模型挂在了墙 ...

  8. [LOJ#2323]「清华集训 2017」小Y和地铁

    [LOJ#2323]「清华集训 2017」小Y和地铁 试题描述 小Y是一个爱好旅行的OIer.一天,她来到了一个新的城市.由于不熟悉那里的交通系统,她选择了坐地铁. 她发现每条地铁线路可以看成平面上的 ...

  9. Loj #2331. 「清华集训 2017」某位歌姬的故事

    Loj #2331. 「清华集训 2017」某位歌姬的故事 IA 是一名会唱歌的女孩子. IOI2018 就要来了,IA 决定给参赛选手们写一首歌,以表达美好的祝愿.这首歌一共有 \(n\) 个音符, ...

随机推荐

  1. Scala 中方法扩展实践

    前言 这个名字不知道取得是否合适,简单来说要干的事情就是给某个类型添加一些扩展方法,此场景在各种语言中都会用到,比如 C# 语言,如果我们使用一个别人写好的类库,而又想给某个类库添加一些自己封装的方法 ...

  2. ECharts(中国地图篇)的使用

    代码html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <me ...

  3. 微信企业号-根据code获取成员信息(过期code)

    二次请求获取成员信息时,会报如下错误: { "errcode": "40029", "errmsg": "invalid code ...

  4. vue分页问题参考 感谢

    https://www.cnblogs.com/zhoulifeng/p/9395295.html

  5. laravel 5.4 导出excel表格

    1.在laravel根目录下面找到一个composer.json文件 打开并在require下面加上一句话,如图所示: 注:以后这个excel的版本号可能还会修改 2.执行 composer inst ...

  6. Jquery 获取 radio选中值,select选中值

    随着Jquery的作用越来越大,使用的朋友也越来越多.在Web中,由于CheckBox.Radiobutton .DropDownList等控件使用的频率比较高,就关系到这些控件在Jquery中的操作 ...

  7. git fork代码并修改胡提交到自己的git仓库

    最近在参加阿里天池大数据中间件比赛(毫无头绪,打酱油中).看参赛要求,需要将官网的git工程clone下来,在此基础上做修改后提交到自己的仓库中. 由于以前并没有使用过git,所以差了比较多的资料,做 ...

  8. 转载http协议

    转载自:https://blog.csdn.net/weixin_38051694/article/details/77777010 1.说一下什么是Http协议 对器客户端和 服务器端之间数据传输的 ...

  9. RNN Train和Test Mismatch

    李宏毅深度学习 https://www.bilibili.com/video/av9770302/?p=8 在看RNN的时候,你是不是也会觉得有些奇怪, Train的过程中, 是把训练集中的结果作为下 ...

  10. day5_函数返回值

    每个函数都有返回值,如果没有在函数里面指定返回值的话,在python里面函数执行完之后,默认会返回一个None,函数也可以有多个返回值,如果有多个返回值的话,会把返回值都放到一个元组中,返回的是一个元 ...