zoukankan      html  css  js  c++  java
  • codeforces round 416 div2 补题 CF 811 A B C D E

    A. Vladik and Courtesy

    水题略过

    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    using namespace std;
    typedef long long int LL;
    int main()
    {
     LL a,b;
     scanf("%I64d%I64d",&a,&b);
     LL num=1;
     while(true)
     	{
     	 if(a<num){printf("Vladik
    ");return 0;}
     	 a-=num;
     	 //b+=num;
     	 num++;
     	 if(b<num){printf("Valera
    ");return 0;}
     	 b-=num;
     	 //a+=num;
     	 num++;
    	}
     return 0;
    } 
    

    B. Vladik and Complicated Book

    给定一个序列, 询问子区间【l,r】的第k小数是不是原位置的数。

    显然可以用主席树维护,不过这道题数据放水了,用暴力一点的方法应该也能过。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N = 100000 + 5;
    
    int a[N], b[N], rt[N * 20], ls[N * 20], rs[N * 20], sum[N * 20],numm[N];
    
    int n, k, tot, sz, ql, qr, x, q, T;
    
    void Build(int& o, int l, int r){
        if(l>r)return ;
    	o = ++ tot;
        sum[o] = 0;
        if(l == r) return;
        int m = (l + r) >> 1;
        Build(ls[o], l, m);
        Build(rs[o], m + 1, r);
    }
    
    void update(int& o, int l, int r, int last, int p){
        o = ++ tot;
        ls[o] = ls[last];
        rs[o] = rs[last];
        sum[o] = sum[last] + 1;
        if(l == r) return;
        int m = (l + r) >> 1;
        if(p <= b[m])  update(ls[o], l, m, ls[last], p);
        else update(rs[o], m + 1, r, rs[last], p);
    }
    
    int query(int ss, int tt, int l, int r, int k){
        if(l == r) return l;
        int m = (l + r) >> 1;
        int cnt = sum[ls[tt]] - sum[ls[ss]];
        if(k <= cnt) return query(ls[ss], ls[tt], l, m, k);
        else return query(rs[ss], rs[tt], m + 1, r, k - cnt);
    }
    
    void work(){
        scanf("%d%d%d", &ql, &qr, &x);
        int xx=x;
        x=(xx-ql+1);
        int ans = query(rt[ql - 1], rt[qr], 1, sz, x);
        if(b[ans]==numm[xx])printf("Yes
    ");
        	else printf("No
    ");
    }
    
    int main(){//freopen("t.txt","r",stdin);
       T=1; 
        while(T--){
            scanf("%d%d", &n, &q);
            for(int i = 1; i <= n; i ++) scanf("%d", a + i), numm[i]=b[i] = a[i];
            sort(b + 1, b + n + 1);
            sz = unique(b + 1, b + n + 1) - (b + 1);
            tot = 0;
            Build(rt[0],1, sz);
            //for(int i = 0; i <= 4 * n; i ++)printf("%d,rt =  %d,ls =  %d, rs = %d, sum = %d
    ", i, rt[i], ls[i], rs[i], sum[i]);
            //for(int i = 1; i <= n; i ++)a[i] = lower_bound(b + 1, b + sz + 1, a[i]) - b;
            for(int i = 1; i <= n; i ++)update(rt[i], 1, sz, rt[i - 1], a[i]);
           // for(int i = 0; i <= 5 * n; i ++)printf("%d,rt =  %d,ls =  %d, rs = %d, sum = %d
    ", i, rt[i], ls[i], rs[i], sum[i]);
            while(q --)work();
        }
        return 0;
    }
    

    C. Vladik and Memorable Trip

    O(n^2)的线性dp 不要想太多。。(我都想到DAG去了。。。)

    代码比较简单,可以直接看懂。

    #include <bits/stdc++.h>
    using namespace std;
    
    vector <int> ps [5010], cs[5010];
    int s[5010] , e[5010];
    bool vis[5010];
    long long dp [5010];
    int main()
    {
    	int n;
    	scanf("%d",&n);
    	vector <int> a (n);
    	for (int i = 0; i < n; i++) {
    		scanf("%d",&a[i]);
    		if (!vis[a[i]]) s[a[i]] = i;
    		vis[a[i]] = 1;
    		e[a[i]] = i;
    	}
    	for (int i = 0; i < n; i++) vis[a[i]] = 0;
    	for (int i = 0; i < n; i++) {
    		int mx = i, rx = 0, lj = i;
    		for (int j = i; j < n; j++) {
    			if (s[a[j]] < i) break;
    			lj = j;
    			mx = max(mx,e[a[j]]);
    			if (!vis[a[j]]) rx ^= a[j];
    			vis[a[j]] = 1;
    			
    			if (mx <= j) {
    				ps[i].push_back(j);
    				cs[i].push_back(rx);
    			}
    		}
    		for (int k = lj; k >= i; k--) vis[a[k]] = 0;
    	}
    	for (int i = n-1; i >= 0; i--) {
    		dp[i] = dp[i+1];
    		for (int j = 0; j < ps[i].size(); j++) {
    			dp[i] = max(dp[i],dp[ps[i][j]+1]+cs[i][j]);
    		}
    	}
    	printf("%I64d
    ",dp[0]);
    }
    

    D. Vladik and Favorite Game

     第一步判断一下按钮是否反转即可。剩下的直接暴力求路径,水题。

    #include<bits/stdc++.h>
    using namespace std;
    #define mp make_pair
    #define ff first
    #define ss second
    #define pb push_back
    
    const int N = 100 + 11;
    
    int use[N][N];
    char a[N][N],b[5];
    vector<pair<int,int> > v,w;
    vector<int> vv;
    
    void dfs(int l, int r)
    {
        use[l][r]=1;
        v.pb(mp(l,r));
        if (a[l][r]=='F') {w=v; return;}
        if (use[l-1][r]==0&&(a[l-1][r]=='.'||a[l-1][r]=='F')) dfs(l-1,r);
        if (use[l+1][r]==0&&(a[l+1][r]=='.'||a[l+1][r]=='F')) dfs(l+1,r);
        if (use[l][r-1]==0&&(a[l][r-1]=='.'||a[l][r-1]=='F')) dfs(l,r-1);
        if (use[l][r+1]==0&&(a[l][r+1]=='.'||a[l][r+1]=='F')) dfs(l,r+1);
        v.pop_back();
    }
    int main()
    {
        int n,m;
        cin>>n>>m;
        int l,r;
        for (int i=1; i<=n; i++)
        for (int j=1; j<=m; j++)
        {
            cin>>a[i][j];
            if (a[i][j]=='F') {l=i; r=j;}
        }
        b[1]='L';
        b[2]='R';
        b[3]='U';
        b[4]='D';
        dfs(1,1);
        for (int i=1; i<w.size(); i++)
        {
            if (w[i].ff==w[i-1].ff)
            {
                if (w[i].ss==w[i-1].ss-1) vv.pb(1); else vv.pb(2);
            } else
            if (w[i].ff==w[i-1].ff-1) vv.pb(3); else vv.pb(4);
        }
        int u1=0,u2=0;
        int x=1,y=1;
        for (int i=0; i<vv.size(); i++)
        {
            if (vv[i]==2&&u1==0)
            {
                cout<<"R"<<endl;
                int xx,yy;
                cin>>xx>>yy;
                u1=1;
                if (x==xx&&y==yy) {swap(b[1],b[2]); cout<<"L"<<endl; cin>>x>>y;}
            } else
            if (vv[i]==4&&u2==0)
            {
                cout<<"D"<<endl;
                int xx,yy;
                cin>>xx>>yy;
                u2=1;
                if (x==xx&&y==yy) {swap(b[3],b[4]); cout<<"U"<<endl; cin>>x>>y;}
            } else
            {
                cout<<b[vv[i]]<<endl;
                cin>>x>>y;
            }
        }
    
    }
    

      

    E. Vladik and Entertaining Flags

    线段树+并查集

    给定一个行数为10 列数10w的矩阵,每个方块是一个整数, 给定l和r 求范围内的联通块数量 所谓联通块即数字相等。

    考虑用二分的方法合并两个联通块,在合并的时候只需要标记边界的元素属于哪个块即可,不用考虑块内的元素,因为它们不会在将来的合并中使用到。

    这样我们就可以做到在常数时间内合并两个块了,这样用线段树维护就没有问题了。

    其实想了一下,用倍增的方法也是可以的,dp[i][k]表示从第i列开始 连续2^k列的联通块,复杂度也是O(nlogn)

    所以用一个线段树维护所有的[l,r]子块,每次查询线段树即可,合并的时候要重新标号。

    重点:对于每个子块,我们只需要知道边界上的元素属于这个子块的哪个联通分量即可(使用并查集维护)

    比赛的时候我也是老想块中的元素怎么维护,就觉得二分难搞了,其实完全不需要考虑。。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 10;
    const int M = 100010;
    
    int n, m, q;
    int a[N][M];
    int state[50], mark[50];
    
    struct Info{
    	int cnt;
    	int left[N];
    	int right[N];
    
    	Info() {
    		cnt = 0;
    		memset(left, 0, sizeof left);
    		memset(right, 0, sizeof right);
    	}
    } tr[M << 2];
    
    Info join(Info &u, Info &v, int p) {
    	Info f;
    	f.cnt = u.cnt + v.cnt;
    	memset(state, 0, sizeof state);
    	for (int k = 0; k < n; k++) {
    		if (a[k][p] == a[k][p + 1]) {
    			int x = u.right[k];
    			int y = v.left[k] + 21;
    			while (state[x]) {
    				x = state[x];
    			}//路径压缩 
    			while (state[y]) {
    				y = state[y];
    			}
    			if (x != y) {
    				f.cnt--;
    				state[y] = x;
    			}
    		}
    	}
    	int g = 1;
    	memset(mark, 0, sizeof mark);
    	for (int k = 0; k < n; k++) {
    		int x = u.left[k];
    		while (state[x]) {
    			x = state[x];
    		}
    		if (mark[x] == 0) {
    			mark[x] = g++;
    		}//从头标号 只需记录左边界和右边界 
    		f.left[k] = mark[x];//重新标记边界 
    		int y = v.right[k] + 21;
    		while (state[y]) {
    			y = state[y];
    		}
    		if (mark[y] == 0) {
    			mark[y] = g++;
    		}
    		f.right[k] = mark[y];//重新标记边界 
    	}
    	return f;
    }
    
    void build(int l, int r, int i) {
    	if (l == r) {
    		for (int k = 0; k < n; k++) {
    			if (k == 0 || a[k][l] != a[k - 1][l]) {
    				tr[i].left[k] = tr[i].right[k] = ++tr[i].cnt;	
    			} else {
    				tr[i].left[k] = tr[i].right[k] = tr[i].left[k - 1];
    			}
    		}
    	} else {
    		int mid = (l + r) >> 1;
    		build(l, mid, i + i);
    		build(mid + 1, r, i + i + 1);
    		tr[i] = join(tr[i + i], tr[i + i + 1], mid);
    	}
    	/*
    	cout << " + " << l << " " << r << "
    ";
    	for (int k = 0; k < n; k++) {
    		cout << tr[i].left[k] << " ";
    	}
    	cout << "
    ";
    	for (int k = 0; k < n; k++) {
    		cout << tr[i].right[k] << " ";
    	}
    	cout << "
    ";
    	*/
    }
    
    void get(int l, int r, int x, int y, int i, Info &res) {
    	if (x <= l && r <= y) {
    		if (l == x) {
    			res = tr[i];
    		} else {
    			res = join(res, tr[i], l - 1);
    		}
    	} else {
    		int mid = (l + r) >> 1;
    		if (mid >= x) {
    			get(l, mid, x, y, i + i, res);
    		}
    		if (mid < y) {
    			get(mid + 1, r, x, y, i + i + 1, res);
    		}
    	}
    }
    
    int main() {
    	scanf("%d %d %d", &n, &m, &q);
    	for (int i = 0; i < n; i++) {
    		for (int j = 1; j <= m; j++) {
    			scanf("%d", &a[i][j]);
    		}
    	}
    	build(1, m, 1);
    	Info res;
    	while (q--) {
    		int l, r;
    		scanf("%d %d", &l, &r);
    		get(1, m, l, r, 1, res);
    		printf("%d
    ", res.cnt);
    	}
    }
    

      

  • 相关阅读:
    fw:Hadoop、Pig、Hive、Storm、NOSQL 学习资源收集【Updating】
    【Azure 环境】用 PowerShell 调用 AAD Token, 以及调用Azure REST API(如资源组列表)
    【Azure 环境】使用Azure中的App Service部署Web应用,以Windows为主机系统是否可以启动防病毒,防恶意软件服务呢(Microsoft Antimalware)?
    【Azure 应用程序见解】通过无代码方式在App Service中启用Application Insights后,如何修改在Application Insights中显示的App Service实例名呢?
    【Azure API 管理】API Management service (APIM) 如何实现禁止外网访问
    【Azure 环境】Azure门户中 Metrics 图表的聚合指标每项具体代表什么意思呢?
    【Azure Redis 缓存】Redis导出数据文件变小 / 在新的Redis复原后数据大小压缩近一倍问题分析
    【Azure 事件中心】在Windows系统中使用 kafkaconsumergroups.bat 查看Event Hub中kafka的consumer groups信息
    RadToolTip (点击按钮,弹出ToolTip)
    Url传值,传入中文,读取时出现乱码的解决方案
  • 原文地址:https://www.cnblogs.com/heisenberg-/p/6914443.html
Copyright © 2011-2022 走看看