• 模拟赛简要题解与心得


    模拟赛简要题解与心得

    最近我的心态炸了,写此博客纪念调侃一下.

    T1 方格纸与直线

    【题目描述】
    小林有一张 n 行 m 列的方格纸,如下所示。

    该方格纸黑白相间,且第一行第一列为黑色。顽皮的亮亮在方格纸上画了一
    条连接左上角和右下角的线段。小林看到方格纸后,马上算出了位于黑色区域的
    线段的长度之和占整条线段长度的比值。现在,他想考考你会不会算。
    【输入格式】
    一行两个整数 n 和 m。
    【输出格式】
    输出一个分数,即题目中所求的比值,用两个由’/’分隔的互质整数表示。
    【样例输入】
    4 6
    【样例输出】
    1/2
    【数据规模】
    对于 50%的数据,n, m <= 10^6;
    对于 100%的数据,1 <= n,m <= 10^9。

    题解

    找规律的好题,但是还是因为时间问题错失了满分的机会.
    题目要求的是比值,故当 m 与 n 不互质时,我们可以求出 m 和 n 的最大
    公约数 d,并将 m /= d, n /= d,并不影响结果。故我们现在假定 m 和 n 互质。若m 和 n 中有一个为偶数, 那么根据对称性, 答案就是 1/2。 如果 m 和 n 均为奇数,
    那么答案就是((n*m+1) / (2*m*n))

    T2 探险

    【题目描述】
    小林和亮亮来到森林中探险, 森林中有一条长度为 S 的小路 (编号从 1 到 S) ,
    且在小路上时常会起雾,亮亮也可以用神光让雾消散。
    小林则关心在某一位置的视野。若位置 x 有浓雾,则位置 x 的视野为 0。若
    从 x 一直到 S 或从 x 一直到 1 全都没有浓雾,则视野为INF。其他情况下,位置x的视野为(max{R - L + 1})
    要满足这个区间内没有浓雾的产生.
    具体来说,会有以下事件发生:
    1、“1 L R”小路的[L, R]部分产生了浓雾;
    2、“2 L R”小路的[L, R]部分浓雾散去了。
    3、“3 X” 查询 X 点的视野。
    一开始,小路上没有任何浓雾。
    【输入格式】
    第一行一个整数,为小路的长度 S。
    第二行一个整数,为事件数 Q。
    接下来 Q 行,每行一个事件,格式如题目描述。
    【输出格式】
    对于每一个询问事件,输出一个整数或一行字符串“INF”,代表所求视野。
    【样例输入】
    5
    5
    1 2 4
    3 1
    3 4
    2 3 3
    3 3
    【样例输出】
    INF
    0
    1
    【数据规模】
    对于 40%的数据,SQ <= 510^7。
    对于 100%的数据,2≤S≤100,000,2≤Q≤200,000,1≤L≤R≤S,1≤X≤S。

    题解

    T1推了很长时间,忘记找规律了,结果T2考场一眼出正解却不敢写.写了分块.不知道怎么的就过了.虽然过了,花了我1.5h的时间,so sad.
    正解:线段树,维护区间的和.如果这个点是雾,则这个点的值为1.然后二分最远到达的l,r即可.
    放上分块的代码吧:
    CODE:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    using namespace std;
    const int maxN = 100000 + 7;
    int a[maxN],belong[maxN],R[maxN],L[maxN];
    int sum[maxN];
    int vis[maxN];
    int n;
    
    inline int read() {
    	int x = 0,f = 1;char c = getchar();
    	while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar();}
    	while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
    	return x * f;
    }
    
    void pushdown(int now) {
    	if(vis[now] == 1) {
    		for(int i = L[now];i <= R[now];++ i) a[i] = 1;
    		sum[now] = R[now] - L[now] + 1;
    	}
    	if(vis[now] == 2) {
    		for(int i = L[now];i <= R[now];++ i) a[i] = 0;
    		sum[now] = 0;
    	}
    	vis[now] = 0;
    	return ;
    }
    
    inline void change_done(int l,int r) {
    	int belong_l = belong[l],belong_r = belong[r];
    	if(belong_l == belong_r) {
    		if(vis[belong_l]) pushdown(belong_l);
    		for(int i = l;i <= r;++ i) a[i] = 1;
    		sum[belong_l] = 0;
    		for(int i = L[belong_l];i <= R[belong_l];++ i)
    			if(a[i]) sum[belong_l] ++;
    		return;
    	}
    	for(int i = belong_l + 1;i < belong_r;++ i) vis[i] = 1,sum[i] = R[i] - L[i] + 1;
    	if(vis[belong_l]) pushdown(belong_l);
    	if(vis[belong_r]) pushdown(belong_r);
    	for(int i = l;i <= R[belong_l];++ i) a[i] = 1;
    	for(int i = L[belong_r];i <= r;++ i) a[i] = 1;
    	sum[belong_l] = sum[belong_r] = 0;
    	for(int i = L[belong_l];i <= R[belong_l];++ i)
    		if(a[i]) sum[belong_l] ++;
    	for(int i = L[belong_r];i <= R[belong_r];++ i)
    		if(a[i]) sum[belong_r] ++;
    	return ;
    }
    
    inline void change_clear(int l,int r) {
    	int belong_l = belong[l],belong_r = belong[r];
    	if(belong_l == belong_r) {
    		if(vis[belong_l]) pushdown(belong_l);
    		for(int i = l;i <= r;++ i) a[i] = 0;
    		sum[belong_l] = 0;
    		for(int i = L[belong_l];i <= R[belong_l];++ i)
    			if(a[i]) sum[belong_l] ++;
    		return;
    	}
    	for(int i = belong_l + 1;i < belong_r;++ i) vis[i] = 2,sum[i] = 0;
    	if(vis[belong_l]) pushdown(belong_l);
    	if(vis[belong_r]) pushdown(belong_r);
    	for(int i = l;i <= R[belong_l];++ i) a[i] = 0;
    	for(int i = L[belong_r];i <= r;++ i) a[i] = 0;
    	sum[belong_l] = sum[belong_r] = 0;
    	for(int i = L[belong_l];i <= R[belong_l];++ i)
    		if(a[i]) sum[belong_l] ++;
    	for(int i = L[belong_r];i <= R[belong_r];++ i)
    		if(a[i]) sum[belong_r] ++;
    	return ;
    }
    
    inline int query(int pos) {
    	int Le = pos,Ri = pos;
    	int belong_pos = belong[pos];
    	if(vis[belong_pos]) pushdown(belong_pos);
    	if(a[pos]) {return 0;}
    	if(pos == n || pos == 1) return -1;
    	for(int i = pos;i <= R[belong_pos];++ i) {
    		if(!a[i]) Ri = i;
    		else break;
    	}
    	for(int i = pos - 1;i >= L[belong_pos];-- i) {
    		if(!a[i]) Le = i;
    		else break;
    	}
    	int belong_end = belong[n],belong_begin = belong[1];
    	if(vis[belong[Ri + 1]]) pushdown(belong[Ri + 1]);
    	if(!a[Ri + 1]) {
    		for(int j = belong_pos + 1;j <= belong_end;++ j) {
    			if(sum[j] != 0) break;
    			Ri = R[j];
    		}
    		if(vis[belong[Ri + 1]]) pushdown(belong[Ri + 1]);
    		for(int j = Ri + 1;j <= n;++ j) {
    			if(!a[j]) Ri = j;
    			else break;
    		}
    	}
    	if(vis[belong[Le - 1]]) pushdown(belong[Le - 1]);
    	if(!a[Le - 1]) {
    		for(int j = belong_pos - 1;j >= belong_begin;-- j) {
    			if(sum[j] != 0) break;
    			Le = L[j];
    		}
    		if(vis[belong[Le - 1]]) pushdown(belong[Le - 1]);
    		for(int j = Le - 1;j >= 1;-- j) {
    			if(!a[j]) Le = j;
    			else break;
    		}
    	}
    	if(Ri == n || Le == 1) return -1;
    	return Ri - Le + 1;
    }
    
    int main() {
    	freopen("explore.in","r",stdin);
    	freopen("explore.out","w",stdout);
    	n = read();
    	int m = read(),type,l,r,x;
    	int q = sqrt(n);
    	for(int i = 1;i <= n;++ i) belong[i] = i / q + 1;
    	for(int i = 1;i <= n;++ i) R[belong[i]] = i;
    	for(int i = n;i >= 1;-- i) L[belong[i]] = i;
    	while(m --) {
    		type = read();
    		if(type == 1) {
    			l = read();r = read();
    			change_done(l,r);
    		}
    		if(type == 2) {
    			l = read();r = read();
    			change_clear(l,r);
    		}
    		if(type == 3) {
    			x = read();
    			int tmp = query(x);
    			if(tmp == -1) {puts("INF");continue;}
    			printf("%d
    ", tmp);
    		}
    	}
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    线段树代码(STD):

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstdlib>
    #define fortodo(i, f, t) for (i = f; i <= t; i++)
    using namespace std;
    
    int lsd[200001], rsd[200001], lsid[200001], rsid[200001], cov[200001], segsize;
    bool emp[200001];
    
    int SEG_Build(int L, int R)
    {
        int Nid = ++segsize;
        lsd[Nid] = L; rsd[Nid] = R;
        emp[Nid] = true; cov[Nid] = 0;
        if (L == R)
            lsid[Nid] = rsid[Nid] = -1;
        else
            {
                lsid[Nid] = SEG_Build(L, (L + R) / 2);
                rsid[Nid] = SEG_Build((L + R) / 2 + 1, R);
            };
        return Nid;
    };
    
    bool SEG_Empty(int Nid)
    {
        if (cov[Nid] == 0) return true;
        if (cov[Nid] == 1) return false;
        return emp[Nid];
    };
    
    void SEG_Reemp(int Nid)
    {
        emp[Nid] = SEG_Empty(lsid[Nid]) && SEG_Empty(rsid[Nid]);
    };
    
    void SEG_Inherit(int Nid)
    {
        if (cov[Nid] == -1) return;
        if (lsd[Nid] == rsd[Nid]) return;
        cov[lsid[Nid]] = cov[Nid];
        cov[rsid[Nid]] = cov[Nid];
        cov[Nid] = -1;
        SEG_Reemp(Nid);
    };
    
    void SEG_Paint(int Nid, int L, int R, int Color)
    {
        SEG_Inherit(Nid);
        if ((L == lsd[Nid]) && (R == rsd[Nid]))
            {
                cov[Nid] = Color;
                return;
            };
        int Div = (lsd[Nid] + rsd[Nid]) / 2;
        if (L >  Div) SEG_Paint(rsid[Nid], L, R, Color);
        if (R <= Div) SEG_Paint(lsid[Nid], L, R, Color);
        if ((L <= Div) && (R > Div))
            {
                SEG_Paint(lsid[Nid], L, Div, Color);
                SEG_Paint(rsid[Nid], Div + 1, R, Color);
            };
        SEG_Reemp(Nid);
    };
    
    bool SEG_Query(int Nid, int L, int R)
    {
        SEG_Inherit(Nid);
        if (SEG_Empty(Nid)) return true;
        if ((L == lsd[Nid]) && (R == rsd[Nid])) return SEG_Empty(Nid);
        int Div = (lsd[Nid] + rsd[Nid]) / 2;
        if (L >  Div) return SEG_Query(rsid[Nid], L, R);
        if (R <= Div) return SEG_Query(lsid[Nid], L, R);
        return SEG_Query(lsid[Nid], L, Div) && SEG_Query(rsid[Nid], Div + 1, R);
    };
    
    int S, Q;
    int i, j;
    int Opt, X, Y;
    
    void Answer(int P)
    {
        if (!SEG_Query(1, P, P))
            {
                printf("0
    ");
                return;
            };
        if ((SEG_Query(1, 1, P)) || (SEG_Query(1, P, S)))
            {
                printf("INF
    ");
                return;
            };
        int L, R, M, Ans[2];
        L = 2; R = P;
        while (L < R)
            {
                M = (L + R) / 2;
                if (SEG_Query(1, M, P))
                    R = M;
                else
                    L = M + 1;
            };
        Ans[0] = L;
        L = P; R = S - 1;
        while (L < R)
            {
                M = (L + R + 1) / 2;
                if (SEG_Query(1, P, M))
                    L = M;
                else
                    R = M - 1;
            };
        Ans[1] = L;
        printf("%d
    ", Ans[1] - Ans[0] + 1);
    };
    
    int main()
    {
        freopen("explore.in", "r", stdin);
        freopen("explore.out", "w", stdout);
        scanf("%d%d", &S, &Q);
        segsize = 0;
        SEG_Build(1, S);
        fortodo(i, 1, Q)
            {
                scanf("%d%d", &Opt, &X);
                if (Opt != 3) scanf("%d", &Y);
                if (Opt == 1) SEG_Paint(1, X, Y, 1);
                if (Opt == 2) SEG_Paint(1, X, Y, 0);
                if (Opt == 3) Answer(X);
            };
        return 0;
    };
    

    3.苹果树

    【题目描述】
    小林有一棵苹果树,树上一共有 n 个节点,n-1 条边,每条边都有长度,且
    有些节点上结有苹果。
    亮亮希望砍掉苹果树的某些边,使得没有任意两个苹果在同一联通块中,并
    且所砍去的边的长度之和最小。
    【输入格式】
    第一行两个整数 n, k, 分别表示树的结点数和含有苹果的结点数。 结点用 0 ~
    n-1 标号。
    接下来 n-1 行,每行三个数 x, y, z,表示一条从 x 到 y 权值为 z 的边。
    接下来 k 行,每行一个数 x,表示编号为 x 的结点上结有一个苹果。
    【输出格式】
    只有一个整数,表示最小的长度之和。
    【样例输入】
    5 3
    2 1 7
    1 0 4
    2 4 9
    1 3 4
    0
    1
    2
    【样例输出】
    11
    【数据规模】
    对于 40%的数据,n <= 20;
    其中 10%的数据和另外 20%的数据,树的形态为一条链;
    对于 100%的数据,2 <= n <= 100000,2 <= k <= n, 1 <= 边权 <= 1000000。

    题解

    实在是没有时间写暴力了,不然40的数据(2^n)枚举子集.再(n)判断联通块.
    (60)的数据直接线段树即可.
    剩下的应该是一个树形D.P
    实在是没有时间了.
    树形 DP。首先任取一个有苹果的结点为根,构建整棵树,接下来自底向上进行动态
    规划。设 f[u]表示以 u 为根的子树中苹果互不连通,且子树中的苹果不与树外的苹果连通的
    最小代价。g[u]表示以 u 为根的子树中苹果互不连通所需的最小代价。
    那么当 u 上有苹果时,
    g[u] = sum (f[v]) (v 为 u 的所有子节点) ;
    f[u] = g[u] + pre[u] (pre[u]为 u 与其父节点连边的权值) 。
    当 u 上无苹果时,
    设 s[u] = sum (f[v]) (v 为 u 的所有子节点)
    则 g[u] = min (s[u] - f[v] + g[v])
    f[u] = min(s[u], g[u] + pre[u)]

    心得

    考场策略出现问题,T1没有找规律,T2一眼题没有写正解,T3没有时间看.
    开场肝T1.
    直接sb了.
    以后模拟赛时应该通读一遍题目.
    希望以后不犯类似的错误.

  • 相关阅读:
    庆贺自己的软件入围中国软件创新大赛,可惜精英奖没有评上。一个笔记本飞了,哈哈,大奖500万呢!
    VMware vSphere开发(2)配置VMware vSphere Web Services SDK的开发环境
    IPhone 视图切换的的2种方法
    Windows系统加固方案
    我们公司原来C++招聘考试题,题目难度正常,没有稀奇古怪的题,如果答对60分以上,恭喜你基本算一个合格的网络开发工程师了。
    算法分析整数划分
    Java反射机制
    Java类集
    设计包含min函数的栈
    ASP.NET学习之Membership
  • 原文地址:https://www.cnblogs.com/tpgzy/p/9780396.html
Copyright © 2020-2023  润新知