*注意:这套题目题面请在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

最新文章

  1. 从list表单序列化后的值转成标准json
  2. 11. KVC And KVO
  3. can&#39;t debug windows service in win7 64bit
  4. c#事务用法
  5. SVG 2D入门13 - svg对决canvas
  6. 点的双联通+二分图的判定(poj2942)
  7. hadoop DataNode实现分析
  8. ubuntu apt-get常用命令的使用
  9. 翻译Android USB HOST API
  10. LA - 5031 - Graph and Queries
  11. svn地址如何更改
  12. Weblogic虚拟目录
  13. 国外支付PayPal
  14. webpack.config.js配置文件
  15. java EE 、java SE 、java ME的区别
  16. ​Django-model
  17. sqlserver 迁移
  18. Vue.js 2.x:组件的定义和注册(详细的图文教程)
  19. ROC曲线(receiver-operating-characteristic curve)-阈值评价标准(转)
  20. Kubernetes学习之路(二十二)之Pod资源调度

热门文章

  1. Gym 100712
  2. js监听手机端点击物理返回键或js监听pc端点击浏览器返回键
  3. java 三大框架 struct2部分 实现增删该查操作
  4. php数组合并方法array_merge + 排序array_multisort方法 array_unique数组去重 array_values数组索引值重新从0开始递增
  5. js中级小知识1
  6. Installing Ruby 2.2 on Centos7
  7. JS------获取一个时间区间的所有天
  8. 浅谈Vue.use
  9. J2EE快速开发框架
  10. Xcode工程编译错误之iOS开发之Xcode9报错 Compiling IB documents for earlier than iOS7 is no longer supported.