zoukankan      html  css  js  c++  java
  • Codeforces Round #416 (Div. 2)

    Problem C. Vladik and Memorable Trip

    题目大意

    有n个人打算坐火车,排成了一列。给定每个人要去的目标城市。将这些人分成若干段,同一段内的人坐在同一节车厢里面。(也可以不分配某个人,即这个人不坐火车)规定去往相同城市的人要么都不坐火车,要么都在火车的同一节车厢里面。定义每节车厢的舒适度为同一节车厢内去往城市的编号的异或和。询问所有车厢的舒适度之和的最大值。

    解题分析

    动态规划。
    定义 dp[i] 表示前i个人坐火车的车厢的舒适度之和的最大值。枚举 j 为 0 ~ i - 1 , 使得 j + 1 ~ i 的人坐在同一车厢,若满足题目条件则更新答案。具体判断过程见程序。

    参考程序

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=5008;
    #define rep(i,x,y) for (int i=x;i<=y;i++)
    #define repd(i,x,y) for (int i=x;i>=y;i--)
    
    int a[N];
    int n;
    int dp[N];
    int l[N],r[N],flag[N];
    
    int main()
    {
    	cin>>n;
    	rep(i,1,n) cin>>a[i];
    	rep(i,1,n)
    	{
    		l[a[i]]=l[a[i]]==0?i:min(l[a[i]],i);
    		r[a[i]]=r[a[i]]==0?i:max(r[a[i]],i);		
    	}
    	rep(i,1,n)
    	{
    		int limit=0;
    		int sum=0;
    		memset(flag,0,sizeof(flag));
    		repd(j,i,1)
    		{
    			if (r[a[j]]>i) break;
    			limit=limit==0?l[a[j]]:min(limit,l[a[j]]);
    			if (limit<=j && !flag[a[j]]) 
    			{
    				flag[a[j]]=1;
    				sum=sum ^ a[j];
    			}
    			if (limit==j)
    				dp[i]=max(dp[i],dp[j-1]+sum);
    		}
    		repd(j,i,1) dp[i]=max(dp[i],dp[j]);
    	}
    	//rep(i,1,n) cout<<dp[i]<<" ";
    	cout<<dp[n]<<endl;
    }
    
    

    Problem D. Vladik and Favorite Game

    题目大意

    交互式题目。
    给一张地图。给出终点和障碍。起点默认为(1,1)。
    每次输出一个方向,会得到一个当前所在位置的输入。
    不过,上下和左右可能是颠倒的,即往上走可能得到一个实际往下走的位置。
    要求给出一定的输出,使得最后走到终点。

    解题分析

    关键在于求出上下和左右是否被颠倒。
    如果某个点上下两个方位都是可以走的,那么可以通过这个点判断出上下是否被颠倒。左右方向同理。
    故只需先判断起点能否判断上下或左右(必然可以判断出一个),然后再那一条直线上找出另一个可以判断出另一个方向的点就行了。
    最后bfs找出一条到达终点的路径。

    参考程序

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rep(i,x,y) for (int i=x;i<=y;++i)
    #define U 0
    #define D 1
    #define L 2
    #define R 3
    const int dx[4]={-1,1,0,0};
    const int dy[4]={0,0,-1,1};
    int a[200][200];
    char s[200];
    int tx,ty,m,n,p=-1,q=-1,X,Y;
    void ptget(int x)
    {
    	if (x==0) printf("U
    ");
    	if (x==1) printf("D
    ");
    	if (x==2) printf("L
    ");
    	if (x==3) printf("R
    ");
    	fflush(stdout);
    	scanf("%d%d",&X,&Y);
    	if (X==tx && Y==ty) exit(0);
    	if (X==-1 || Y==-1) exit(0);
    }
    
    bool move_lr(int x,int y)
    {
    	if (a[x][y-1]==-1) return 0;
    	if (a[x][y+1]==-1) return 0;
    	return 1;
    }
    bool move_ud(int x,int y)
    {
    	if (a[x-1][y]==-1) return 0;
    	if (a[x+1][y]==-1) return 0;
    	return 1;
    }
    struct node
    {
    	int x,y;
    };
    queue <node> Q;
    int dis[200][200];
    int main()
    {
    	cin.sync_with_stdio(0);
    	cin>>m>>n;
    	rep(i,1,m)
    	{
    		cin>>s+1;
    		rep(j,1,n)
    		{
    			if (s[j]=='*') a[i][j]=-1; else a[i][j]=0;
    			if (s[j]=='F') tx=i,ty=j;
    		}
    	}
    	if (move_lr(1,1))
    	{
    		ptget(L);
    		if (Y==1)
    		{
    			p=0;
    		}
    		else
    		{
    			p=1;
    			ptget(L ^ p);
    		}
    		int way;
    		rep(i,1,n) if (move_ud(1,i)) {way=i;break;}
    		rep(i,1,way-1) ptget(R ^ p);
    		ptget(U);
    		if (X==1)
    		{
    			q=0;
    		}
    		else
    		{
    			q=1;
    			//ptget(U ^ q);
    		}
    		//rep(i,1,way-1) ptget(L ^ p);
    	}
    	else
    	{
    		ptget(U);
    		if (X==1)
    		{
    			q=0;
    		}
    		else
    		{
    			q=1;
    			ptget(U ^ q);
    		}
    		int way;
    		rep(i,1,m) if (move_lr(i,1)) {way=i;break;}
    		rep(i,1,way-1) ptget(D ^ q);
    		ptget(L);
    		if (Y==1)
    		{
    			p=0;
    		}
    		else
    		{
    			p=1;
    		}
    	}
    	dis[tx][ty]=1; Q.push((node){tx,ty});
    	while (!Q.empty())
    	{
    		node xh = Q.front(); Q.pop();
    		rep(i,0,3)
    		{
    			int x=xh.x+dx[i];
    			int y=xh.y+dy[i];
    			if (x>=1 && x<=m && y>=1 && y<=n && dis[x][y]==0 && a[x][y]==0)
    			{
    				dis[x][y]=dis[xh.x][xh.y]+1;
    				Q.push((node){x,y});
    			}
    		}	
    	}
    	int nowx=X,nowy=Y;
    	while (nowx!=tx || nowy!=ty)
    	{
    		int dir=-1;
    		rep(i,0,3)
    		{
    			int x=nowx+dx[i];
    			int y=nowy+dy[i];
    			if (x>=1 && x<=m && y>=1 && y<=n && dis[x][y]==dis[nowx][nowy]-1)
    			{
    				dir=i;
    				break;
    			}
    		}
    		if (dir==0 || dir==1) ptget(dir ^ q); else ptget(dir ^ p);
    		nowx = X; nowy = Y;
    	}
    }
    

    Problem E Vladik and Entertaining Flags

    题目大意

    有一张m*n的矩阵,每个点上有一个数字,所有相邻的相同数字被称为一段。
    有Q个询问,每次给出 l,r,询问在(1 * l ~ m * r)矩阵中有多少段数字。
    1 <= m <= 10, 1 <= n, q <= 10 ^ 5

    解题分析

    由于m很小,考虑用线段树来做。
    记录一下每段区间的左边和右边的颜色以及段落数,如果左边的颜色块和右边的颜色块是连通的话,那么用相同的数字来表示。
    每次合并的时候用并查集来维护。

    参考程序

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e5 + 8;
    const int M = 20; 
    struct node
    {
    	int sum;
    	int a[M];
    	int b[M];
    }T[N << 2];
    
    int a[M][N];
    int f[N], id[N];
    
    int n, m, q;
    
    int find(int x)
    {
    	if (f[x] == x) return x;
    	return f[x] = find(f[x]);
    }
    
    void merge(node &rt, node &l, node &r, int lpos, int rpos)
    {
    	rt.sum = l.sum + r.sum;
    	for (int i = 0; i < m; ++i)
    	{
    		f[i] = l.a[i];
    		f[i + m] = l.b[i];
    		f[i + m * 2] = r.a[i] + m * 2;
    		f[i + m * 3] = r.b[i] + m * 2;
    	}
    	for (int i = 0; i < m; ++i)
    	{
    		if (a[i][lpos] == a[i][rpos] && f[find(i +  m * 2)] != f[find(i + m)])
    		{
    			f[find(i +  m * 2)] = f[find(i + m)];
    			rt.sum--;
    		}
    	}		
    	for (int i = 0; i < m * 4; ++i) f[i] = find(f[i]), id[f[i]] = -1; 
    	for (int i = 0; i < m; ++i)
    	{
    		if (id[f[i]] == -1) id[f[i]] = i;
    		rt.a[i] = id[f[i]];
    	}
    	for (int i = m * 3; i < m * 4; ++i)
    	{
    		if (id[f[i]] == -1) id[f[i]] = i - m * 2;
    		rt.b[i - m * 3] = id[f[i]];	
    	}
    }
    
    void query(int L, int R, int l, int r, int rt, node &ans)
    {
    	if (L <= l && r <= R)
    	{
    		ans = T[rt];
    		return;
    	}
    	int mid = l + r >> 1;
    	if (R <= mid) {query(L, R, l, mid, rt << 1, ans); return;}
    	if (mid < L) {query(L, R, mid + 1, r, rt << 1 | 1, ans); return;}
    	node p, q;
    	query(L, R, l, mid, rt << 1, p);
    	query(L, R, mid + 1, r, rt << 1 | 1, q);
    	merge(ans, p, q, mid, mid + 1);
    }
    
    void build(int l, int r, int rt)
    {
    	if (l == r)
    	{
    		T[rt].sum = 0;
    		for (int i = 0; i < m; ++i) 
    			if (i == 0 || a[i][l] != a[i - 1][l])
    			{
    				T[rt].a[i] = T[rt].b[i] = i;
    				T[rt].sum++;
    			}
    			else
    			{
    				T[rt].a[i] = T[rt].b[i] = T[rt].a[i-1];
    			}
    		return;
    	}
    	int mid = l + r >> 1;
    	build(l, mid, rt << 1);
    	build(mid + 1, r, rt << 1 | 1);
    	merge(T[rt], T[rt << 1], T[rt << 1 | 1], mid, mid + 1);
    }
    int main()
    {
    	cin.sync_with_stdio(0);
    	cin >> m >> n >> q;
    	for (int i = 0; i < m; ++i)
    		for (int j = 1; j <= n; ++j)
    			cin >> a[i][j];
    	build(1, n, 1);
    	node ans;
    	for (int i = 0; i < q; ++i)
    	{
    		int l, r;
    		cin >> l >> r;
    		query(l, r, 1, n, 1, ans);
    		cout << ans.sum << endl;
    	}
    }
    
  • 相关阅读:
    c#实现windows远程桌面连接程序
    基于.NET平台常用的框架整理
    c#无限循环线程如何正确退出
    c# 内存的具体表现- 通用类型系统 深拷贝 浅拷贝 函数传参
    coco2d-x convertToWorldSpace介绍
    Effective C++条款20:宁以pass-by-reference-to-const替换pass-by-value。Test code
    函数指针与指针函数返回值的区别
    游戏开发那些事
    lua 根据指定字符拆分table字符串(转载)
    实习和学习的双重压力
  • 原文地址:https://www.cnblogs.com/rpSebastian/p/6916245.html
Copyright © 2011-2022 走看看