zoukankan      html  css  js  c++  java
  • $NOIP 2016 Day1$ 模拟考试 题解报告

    (NOIP 2016 Day1) 模拟考试 题解报告

    得分情况

    (T1) (85 Pts)

    (T2) (15 Pts)

    (T3) (100 Pts)

    总分: (200 Pts)

    考试过程

    看完 (T1) 半个小时写完了 (T2) 不可做 去看 (T3) 然后写 + 调两个小时 回头写 (T2) 没写完 过了编译直接交了

    题解

    (T1) 玩具谜题

    模拟

    应该是没有和我写的一样的 比较短 要注意一下细节 想到了取模 没想到会加爆

    代码

    /*
      Time: 6.13
      Worker: Blank_space
      Source:
    */
    /*--------------------------------------------*/
    #include<cstdio>
    #include<string>
    #include<cstring>
    #include<iostream>
    /*--------------------------------------头文件*/
    const int B = 1e5 + 7;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    /*------------------------------------常量定义*/
    inline void File() {
    	freopen("toy.in", "r", stdin);
    	freopen("toy.out", "w", stdout);
    }
    /*----------------------------------------文件*/
    int n, m, to[B], pos;
    std::string na[B];
    /*------------------------------------变量定义*/
    inline int read() {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    /*----------------------------------------快读*/
    
    /*----------------------------------------函数*/
    int main() {
    //	File(); 
    	n = read(); m = read(); pos = 1;
    	for(int i = 1; i <= n; i++) {to[i] = read(); if(!to[i]) to[i] = -1; std::cin >> na[i];}
    	for(int i = 1; i <= m; i++)
    	{
    		int x = read(), y = read(); if(!x) x = -1;
    		int z = x * to[pos]; while(~z && pos <= y) pos += n;
    		pos -= z * y; if(pos > n) pos %= n;
    	}
    	std::cout << na[pos];
    	return 0;
    }
    

    (T2) 天天爱跑步

    时间不够... 只想到了 (O(n^2)) 的做法 样例都没跑 过了编译直接交了 后来发现不分测试点的话能有 (25 Pts) 分了测试点反而挂了 (10 Pts)

    (25 Pts) 暴力

    起点和终点求 (LCA) 向上暴跳 开桶记录答案即可

    void up(int x, int y) {
    	_cnt = 0;
    	while(x != y) _c[x][_cnt++]++, x = fa[x];
    	_c[x][_cnt]++;
    }
    void down(int x, int y) {
    	_cnt += dep[x] - dep[y];
    	while(x != y) _c[x][_cnt--]++, x = fa[x];
    }
    void work1() {
    	dfs(1, 0); dfs2(1, 1);
    	for(int i = 1; i <= m; i++)
    	{
    		int lca = LCA(s[i], t[i]);
    		up(s[i], lca); down(t[i], lca);
    	}
    	for(int i = 1; i <= n; i++) ans[i] = _c[i][w[i]];
    	for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
    }
    

    (15 Pts)

    从一个点出发只有向左或向右两种情况 对于在 (j) 点的观察员 有

    [s = j - w_j\ s = j + w_j ]

    为分别向右向左

    类似差分的思想用桶统计贡献 从左向右扫一遍 桶中加入该点向右出发的路径条数 按照上面统计合法的节点个数 在左侧的能到达这个点位置的桶(--) 再从右向左扫一遍 即为答案

    for(int i = 1; i <= m; i++) s[i] = read(), t[i] = read(), cs[s[i]].push_back(t[i]), ct[t[i]].push_back(s[i]);
    void work2() {
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 0; j < cs[i].size(); j++) if(i <= cs[i][j]) o[i]++;
    		if(i > w[i]) ans[i] += o[i - w[i]];
    		for(int j = 0; j < ct[i].size(); j++) if(ct[i][j] <= i) o[ct[i][j]]--;
    	}
    	memset(o, 0, sizeof o);
    	for(int i = n; i >= 1; i--)
    	{
    		for(int j = 0; j < cs[i].size(); j++) if(i > cs[i][j]) o[i]++;
    		if(i + w[i] <= n) ans[i] += o[i + w[i]];
    		for(int j = 0; j < ct[i].size(); j++) if(ct[i][j] > i) o[ct[i][j]]--;
    	}
    	for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
    }
    

    (20 Pts) 所有起点都为 (1)

    直接以 (1) 为根 当一个点 (i)(w_i = dep_i) (这里我的深度是从一开始的 实际代码中要减一)时 这个点能观察到的就是以该点为根的子树中终点的个数 否则为 (0)

    void dfs3(int u, int pre) {
    	for(int i = head[u]; i; i = e[i].nxt)
    	{
    		int v = e[i].v; if(v == pre) continue;
    		dfs3(v, u); _siz[u] += _siz[v];
    	}
    	if(w[u] == dep[u] - 1) ans[u] = _siz[u];
    }
    void work3() {
    	for(int i = 1; i <= m; i++) _siz[t[i]]++;
    	dfs3(1, 0);
    	for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
    }
    

    (20 Pts) 所有终点都为 (1)

    直接 (1) 为根 当一个点 (i)(w_i + dep_i = l) (其中 (l) 为链长) 时 有贡献 (dfs) 开桶记录 求增量即为答案

    void dfs4(int u, int pre) {
    	int k = o[w[u] + dep[u] - 1]; o[dep[u] - 1] += oo[u];
    	for(int i = head[u]; i; i = e[i].nxt) if(e[i].v != pre) dfs4(e[i].v, u);
    	ans[u] += o[w[u] + dep[u] - 1] - k;
    }
    void work4() {
    	for(int i = 1; i <= m; i++) oo[s[i]]++;
    	dfs4(1, 0);
    	for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
    }
    

    (20 Pts) 正解

    每一条路径可以分为两部分 一部分向上另一部分向下 向上的时候对于 (i)(dep_i + w_i = dep_s) 时 能观察到 向下的时候 对于 (i)(dep_i + w_i = dep_t - l + 1) ((l) 仍为链长) 时 能观察到 求 (LCA) 进行树上差分

    但是这个题卡了一手 (vector) 导致不开 (O_2) 过不去...

    代码

    void dfs(int u, int pre) {
    	int k = o[w[u] + dep[u] - 1] + oo[dep[u] - w[u] - 1];
    	for(int i = 0; i < cs[u].size(); i++) o[cs[u][i]]++;
    	for(int i = 0; i < ct[u].size(); i++) oo[ct[u][i]]++;
    	for(int i = 0; i < ks[u].size(); i++) o[ks[u][i]]--;
    	for(int i = 0; i < kt[u].size(); i++) oo[kt[u][i]]--;
    	for(int i = head[u]; i; i = e[i].nxt) if(e[i].v != pre) dfs(e[i].v, u);
    	ans[u] = o[w[u] + dep[u] - 1] + oo[dep[u] - w[u] - 1] - k;
    }
    void work() {
    	for(int i = 1; i <= m; i++)
    	{
    		int lca = LCA(s[i], t[i]);
    		l[i] = dep[s[i]] + dep[t[i]] - 2 * dep[lca];
    		cs[s[i]].push_back(dep[s[i]] - 1);
    		ct[t[i]].push_back(dep[t[i]] - 1 - l[i]);
    		ks[lca].push_back(dep[s[i]] - 1);
    		kt[fa[lca]].push_back(dep[t[i]] - 1 - l[i]);
    	}
    	dfs(1, 0);
    	for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
    }
    

    完整代码

    /*
      Time: 6.14
      Worker: Blank_space
      Source:
    */
    /*--------------------------------------------*/
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    #define Abs(x) ((x) < 0 ? -(x) : (x))
    #define Max(x, y) ((x) > (y) ? (x) : (y))
    #define Min(x, y) ((x) < (y) ? (x) : (y))
    #define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
    /*--------------------------------------头文件*/
    const int B = 3e5 + 7;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    /*------------------------------------常量定义*/
    inline void File() {
    	freopen("running.in", "r", stdin);
    	freopen("running.out", "w", stdout);
    }
    /*----------------------------------------文件*/
    int n, m, w[B], s[B], t[B], vis[B], ans[B], siz[B], fa[B], son[B], top[B], dfn[B], dep[B], cnt, _c[1000][1000], _cnt;
    int o[B], oo[B], _siz[B], l[B];
    std::vector <int> cs[B], ct[B], ks[B], kt[B];
    struct edge {int v, nxt;} e[B << 1];
    int head[B], ecnt;
    /*------------------------------------变量定义*/
    inline int read() {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    /*----------------------------------------快读*/
    void add_edge(int u, int v) {e[++ecnt] = (edge){v, head[u]}; head[u] = ecnt;}
    void dfs1(int u, int pre) {
    	siz[u] = 1; fa[u] = pre; dep[u] = dep[pre] + 1;
    	for(int i = head[u]; i; i = e[i].nxt)
    	{
    		int v = e[i].v; if(v == pre) continue;
    		dfs1(v, u); siz[u] += siz[v];
    		if(siz[son[u]] < siz[v]) son[u] = v;
    	}
    }
    void dfs2(int u, int tp) {
    	top[u] = tp; dfn[u] = ++cnt;
    	if(!son[u]) return ; dfs2(son[u], tp);
    	for(int i = head[u]; i; i = e[i].nxt)
    	{
    		int v = e[i].v; if(v == fa[u] || v == son[u]) continue;
    		dfs2(v, v);
    	}
    }
    int LCA(int x, int y) {
    	while(top[x] != top[y])
    	{
    		if(dep[top[x]] < dep[top[y]]) Swap(x, y);
    		x = fa[top[x]];
    	}
    	if(dep[x] > dep[y]) Swap(x, y);
    	return x;
    }
    void up(int x, int y) {
    	_cnt = 0;
    	while(x != y) _c[x][_cnt++]++, x = fa[x];
    	_c[x][_cnt]++;
    }
    void down(int x, int y) {
    	_cnt += dep[x] - dep[y];
    	while(x != y) _c[x][_cnt--]++, x = fa[x];
    }
    void work1() {
    	for(int i = 1; i <= m; i++)
    	{
    		int lca = LCA(s[i], t[i]);
    		up(s[i], lca); down(t[i], lca);
    	}
    	for(int i = 1; i <= n; i++) ans[i] = _c[i][w[i]];
    	for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
    }
    void work2() {
    	for(int i = 1; i <= m; i++) cs[s[i]].push_back(t[i]), ct[t[i]].push_back(s[i]);
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 0; j < cs[i].size(); j++) if(i <= cs[i][j]) o[i]++;
    		if(i > w[i]) ans[i] += o[i - w[i]];
    		for(int j = 0; j < ct[i].size(); j++) if(ct[i][j] <= i) o[ct[i][j]]--;
    	}
    	memset(o, 0, sizeof o);
    	for(int i = n; i >= 1; i--)
    	{
    		for(int j = 0; j < cs[i].size(); j++) if(i > cs[i][j]) o[i]++;
    		if(i + w[i] <= n) ans[i] += o[i + w[i]];
    		for(int j = 0; j < ct[i].size(); j++) if(ct[i][j] > i) o[ct[i][j]]--;
    	}
    	for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
    }
    void dfs3(int u, int pre) {
    	for(int i = head[u]; i; i = e[i].nxt)
    	{
    		int v = e[i].v; if(v == pre) continue;
    		dfs3(v, u); _siz[u] += _siz[v];
    	}
    	if(w[u] == dep[u] - 1) ans[u] = _siz[u];
    }
    void work3() {
    	for(int i = 1; i <= m; i++) _siz[t[i]]++;
    	dfs3(1, 0);
    	for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
    }
    void dfs4(int u, int pre) {
    	int k = o[w[u] + dep[u] - 1]; o[dep[u] - 1] += oo[u];
    	for(int i = head[u]; i; i = e[i].nxt) if(e[i].v != pre) dfs4(e[i].v, u);
    	ans[u] += o[w[u] + dep[u] - 1] - k;
    }
    void work4() {
    	for(int i = 1; i <= m; i++) oo[s[i]]++;
    	dfs4(1, 0);
    	for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
    }
    void dfs(int u, int pre) {
    	int k = o[w[u] + dep[u] - 1] + oo[dep[u] - w[u] - 1];
    	for(int i = 0; i < cs[u].size(); i++) o[cs[u][i]]++;
    	for(int i = 0; i < ct[u].size(); i++) oo[ct[u][i]]++;
    	for(int i = 0; i < ks[u].size(); i++) o[ks[u][i]]--;
    	for(int i = 0; i < kt[u].size(); i++) oo[kt[u][i]]--;
    	for(int i = head[u]; i; i = e[i].nxt) if(e[i].v != pre) dfs(e[i].v, u);
    	ans[u] = o[w[u] + dep[u] - 1] + oo[dep[u] - w[u] - 1] - k;
    }
    void work() {
    	for(int i = 1; i <= m; i++)
    	{
    		int lca = LCA(s[i], t[i]);
    		l[i] = dep[s[i]] + dep[t[i]] - 2 * dep[lca];
    		cs[s[i]].push_back(dep[s[i]] - 1);
    		ct[t[i]].push_back(dep[t[i]] - 1 - l[i]);
    		ks[lca].push_back(dep[s[i]] - 1);
    		kt[fa[lca]].push_back(dep[t[i]] - 1 - l[i]);
    	}
    	dfs(1, 0);
    	for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
    }
    /*----------------------------------------函数*/
    int main() {
    	File();
    	n = read(); m = read();
    	for(int i = 1; i < n; i++)
    	{
    		int x = read(), y = read();
    		add_edge(x, y); add_edge(y, x);
    	}
    	for(int i = 1; i <= n; i++) w[i] = read();
    	for(int i = 1; i <= m; i++) s[i] = read(), t[i] = read();
    	dfs1(1, 0); dfs2(1, 1);
    	if(n <= 1000) work1();
    	else if(n == 99994) work2();
    	else if(n == 99995) work3();
    	else if(n == 99996) work4();
    	else work();
    	return 0;
    }
    

    (T3) 换教室

    做过

    点比较少 先跑全源最短路 然后 (DP)

    代码

    /*
      Time: 6.13
      Worker: Blank_space
      Source: 
    */
    /*--------------------------------------------*/
    #include<cstdio>
    #include<cstring>
    #define Min(x, y) ((x) < (y) ? (x) : (y))
    /*--------------------------------------头文件*/
    const double INF = 0x3f3f3f3f;
    /*------------------------------------常量定义*/
    inline void File() {
    	freopen("classroom10.in", "r", stdin);
    //	freopen("classroom.out", "w", stdout);
    }
    /*----------------------------------------文件*/
    int n, m, v, e, dis[310][310], c[2021], d[2021];
    double f[2021][2021][2], ans = INF, p[2021];
    /*------------------------------------变量定义*/
    inline int read() {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    /*----------------------------------------快读*/
    
    /*----------------------------------------函数*/
    int main() {
    	File();
    	n = read(); m = read(); v = read(); e = read();
    	memset(dis, 63, sizeof dis);
    	for(int i = 1; i <= n; i++) c[i] = read();
    	for(int i = 1; i <= n; i++) d[i] = read();
    	for(int i = 1; i <= n; i++) scanf("%lf", &p[i]);
    	for(int i = 1; i <= e; i++)
    	{
    		int x = read(), y = read(), z = read();
    		dis[x][y] = dis[y][x] = Min(dis[x][y], z);
    	}
        for(int l = 1; l <= v; l++) for(int i = 1; i <= v; i++) for(int j = 1; j <= v; j++) dis[i][j] = Min(dis[i][j], dis[i][l] + dis[l][j]);
        for (int i = 1; i <= v; i++) dis[i][i] = dis[i][0] = dis[0][i] = 0;
    	for(int i = 0; i <= n; i++) for(int j = 0; j <= m; j++) f[i][j][0] = f[i][j][1] = INF;
        f[1][0][0] = f[1][1][1] = 0;
        for(int i = 2; i <= n; i++)
    	{
        	f[i][0][0] = f[i - 1][0][0] + dis[c[i - 1]][c[i]];
        	for(int j = 1; j <= Min(i, m); j++)
        		f[i][j][0] = Min(f[i][j][0], Min(f[i - 1][j][0] + dis[c[i - 1]][c[i]], f[i - 1][j][1] + p[i - 1] * dis[d[i - 1]][c[i]] + (1 - p[i - 1]) * dis[c[i - 1]][c[i]])),
        		f[i][j][1] = Min(f[i][j][1], Min(f[i - 1][j - 1][0] + p[i] * dis[c[i - 1]][d[i]] + (1 - p[i]) * dis[c[i - 1]][c[i]], f[i - 1][j - 1][1] + p[i - 1] * p[i] * dis[d[i - 1]][d[i]] + (1 - p[i - 1]) * p[i] * dis[c[i - 1]][d[i]] + p[i - 1] * (1 - p[i]) * dis[d[i - 1]][c[i]] + (1 - p[i - 1]) * (1 - p[i]) * dis[c[i - 1]][c[i]]));
        }
    	for(int i = 0; i <= m; i++) ans = Min(ans, Min(f[n][i][0], f[n][i][1]));
    	printf("%.2lf", ans);
    	return 0;
    }
    
    
  • 相关阅读:
    Postfix之mail.cf
    利用 Postfix 抵擋垃圾信
    安装webmin
    Win7 登入提示临时漫游档案
    squid 延伸
    禁止VMware用户在系统里删除网卡的操作的方法
    Squid Proxy Server 3.1
    使用RBL拦截垃圾邮件
    建置 POSTFIX 服务器
    Seednet 访问路径
  • 原文地址:https://www.cnblogs.com/blank-space-/p/14882189.html
Copyright © 2011-2022 走看看