2015 China Collegiate Programming Contest

唉!弱渣都没机会去比赛!

//代码还没提交过,不知道对不对,等题目挂出来再交。(已提交)

<题目连接(pdf)>

<提交地址>: uestc online judge

<提交地址>:hdu

A.Secrete Master Plan 

题意:给定2*2的矩阵A和B,问A是否能通过旋转得到B?

分析:模拟,把A转几下?

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;

int a[10],b[10],temp[10];

void change()
{
	temp[3]=a[1];
	temp[4]=a[3];
	temp[2]=a[4];
	temp[1]=a[2];
	
	a[1]=temp[1];
	a[2]=temp[2];
	a[3]=temp[3];
	a[4]=temp[4];
}

bool check(int *t,int *f)
{
	if(t[1]==f[1] && t[2]==f[2] && t[3]==f[3] && t[4]==f[4])
		return true;
	return false;
}

int main()
{
	int ncase,i;
	scanf("%d",&ncase);
	for(int T=1;T<=ncase;T++)
	{
		scanf("%d%d%d%d",&a[1],&a[2],&a[3],&a[4]);
		scanf("%d%d%d%d",&b[1],&b[2],&b[3],&b[4]);
		for(i=1;i<=5;i++,change())	
			if(check(a,b))
				break;
		printf("Case #%d: %s\n",T,i>5?"IMPOSSIBLE":"POSSIBLE");
	}
	return 0;
}

C.The Battle of Chibi

题意:在长度为n的序列中,求长度为m的单调递增序列的个数?

分析:记dp[i][j]表示当前递增序列长度为i,最后一个数字的下标为j。用三层循环肯定不行。先把所有的数离散化,再用树状数组加快找下标在j前面,且值比a[j]小的长度为i-1的方案数。

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;
const int maxn = 1007;
const LL mod = 1e9+7;
int lowbit[maxn],a[maxn],f[maxn];
LL tree[maxn],dp[maxn][maxn];

void add(LL &a,LL b)
{
	a+=b;
	while(a>=mod)
		a-=mod;
}

void Init()
{
	for(int i=1;i<maxn;i++)
		lowbit[i]=i&-i;	
}

void update(int x,LL v)
{
	for(int i=x;i<maxn;i+=lowbit[i])
		add(tree[i],v);
}
LL query(int x)
{
	LL ret(0);
	for(int i=x;i>=1;i-=lowbit[i])
		add(ret,tree[i]);
	return ret;
}

int main()
{
	Init();
	int ncase,i,j,n,m;
	scanf("%d",&ncase);
	for(int T=1;T<=ncase;T++)
	{
		scanf("%d%d",&n,&m);
		for(i=0;i<n;i++)
		{
			scanf("%d",&a[i]);
			f[i]=a[i];
		}
		sort(f,f+n);
		int tail=unique(f,f+n)-f;
		for(i=0;i<n;i++)
			a[i]=lower_bound(f,f+tail,a[i])-f+1;
			
		for(i=0;i<n;i++)
			dp[1][i]=1;
		for(i=2;i<=m;i++)
		{
			memset(tree,0,sizeof(tree));
			for(j=0;j<n;j++)
			{
				dp[i][j]=query(a[j]-1);
			//	printf("q:%d %lld\n",a[j]-1,query(a[j]-1));
			 	update(a[j],dp[i-1][j]);
			}
		}
		LL ans=0;
		for(i=0;i<n;i++)
			add(ans,dp[m][i]);
		printf("Case #%d: %lld\n",T,ans);
	}
	return 0;
}

D.Pick The Sticks

题意:从n个金条里面选出一些来,放在一条长为L的线段上(不能重叠,并且保证金条的中心在线段上),使价值最大。问最大价值?

分析:假如金条必须完完全全放在线段上,那么这个题就是01背包了。但是这个题是允许最多两个金条可以只有一半放在线段上。记dp[i][j][0/1/2],表示处理了前i个金条,容量为j,有0/1/2个金条只有一半在线段上的最大价值。那么对于一个金条,有三种选择,不选、全部放在线段上和一半放在线段上。

代码:

</pre><pre name="code" class="cpp">#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;

LL dp[2][4007][3];
int v[1007],w[1007];

void Max(LL &ans,LL &a)
{
	ans=(ans>a?ans:a);
}
int main()
{
	int ncase,i,j,k;
	int L,n;
	scanf("%d",&ncase);
	for(int T=1;T<=ncase;T++)
	{
		scanf("%d%d",&n,&L);
		L<<=1;
		LL ans=0;
		for(i=1;i<=n;i++)
		{
			scanf("%d%d",&w[i],&v[i]);
			w[i]<<=1;
			ans=ans>v[i]?ans:v[i];
		}
		int cur=0;
		memset(dp,0,sizeof(dp));
		for(i=1;i<=n;i++)
		{
			cur^=1;
			for(j=0;j<=L;j++)
				for(k=0;k<3;k++)
					dp[cur][j][k]=dp[cur^1][j][k];
			for(j=L;j>=w[i]/2;j--)
			{
				for(k=0;k<3;k++)
				{
					if(j>=w[i])
						dp[cur][j][k]=max(dp[cur][j][k],dp[cur^1][j-w[i]][k]+v[i]);
					if(k && j>=w[i]/2)
						dp[cur][j][k]=max(dp[cur][j][k],dp[cur^1][j-w[i]/2][k-1]+v[i]);
					Max(ans,dp[cur][j][k]);
				}
			}
		}
		printf("Case #%d: %lld\n",T,ans);
	}
	return 0;
}


E.ba Gua Zhen

题意:在一个连通图上找一个回路(从起点出发回到起点),使得回路上的所有经过的路径上的权值异或和最大。(如果一条路径走了x次,结果要异或x下)。

分析:①先把所有独立的回路的异或和找出来。②那么问题就转变为在n个数里面选任意多的数使得异或和最大。

对于①用dfs搜,搜的过程中记录当前位置由哪里来,使得不往回走。如果一个点被重复访问,说明形成回路。

对于②高斯消元

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;
const int maxn = 1e5+7;
struct node
{
	int id,next;
	LL w;
}List[maxn<<4];
int head[maxn],cnt;

void Clear()
{
	cnt=0;
	memset(head,-1,sizeof(head));
}
void add(int u,int v,LL w) // u-->v
{
	List[cnt].id=v;
	List[cnt].w=w;
	List[cnt].next=head[u];
	head[u]=cnt++;
}

LL XOR[maxn<<4],num,buf[maxn];//buf[i]表示从起点到i的异或和 
bool visit[maxn];
void dfs(int cur,int per,LL value)
{
	visit[cur]=true;
	for(int i=head[cur];~i;i=List[i].next) if(List[i].id!=per)
	{
		int to=List[i].id;
		LL w=List[i].w;
		if(visit[to])
		{
			XOR[num++]=value^w^buf[to];
			continue ;
		}
		buf[to]=value^w;
		dfs(to,cur,value^w);
	}
}

LL base[65];
LL guass(int n)
{
	memset(base,0,sizeof(base));
	for(int i=0;i<n;i++)
	{
		LL cur=XOR[i];
		for(int j=59;j>=0;j--)
		{
			if((1ll<<j)&cur)
			{
				if(base[j]==0)
				{
					base[j]=cur;
					break;
				}
				else
				{
					cur^=base[j];
				}
			}
		}
	}

	LL ret=0;
	for(int i=0;i<60;i++)
		for(int j=i+1;j<60;j++)
			if((base[j]>>i)&1)
				base[j]^=base[i];
	for(int i=59;i>=0;i--)
		ret^=base[i];
	return ret;
}

int main()
{
	int nCase,i,j,u,v,n,m;
	scanf("%d",&nCase);
	for(int T=1;T<=nCase;T++)
	{
		scanf("%d%d",&n,&m);
		Clear();
		for(i=1;i<=m;i++)
		{
			LL w;
			scanf("%d %d %lld",&u,&v,&w);
			add(u,v,w);
			add(v,u,w);
		}
		num=0;
		memset(visit,0,sizeof(visit));
		memset(buf,0,sizeof(buf));
		dfs(1,-1,0);
		printf("Case #%d: %lld\n",T,guass(num));
	}
	return 0;
}                                                                                                                                     


G.Ancient Go

题意:给定一副围棋的局面,先将所有的已经死掉的'x'去掉,再将所有的已经死掉的'o'去掉,问在添加一个'x'是否能吃掉至少一个‘o’?

分析:先算出'x'的连通块边缘有多少个'.'与之相连,如果是0个就把这个连通块去掉,同理去掉‘o’。然后再算‘o’的连通块边缘有多少个'.'与之相连,若存在一个为1的,就满足条件,否则不满足。

代码:


#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;

char maze[12][12];

set <int > st;
bool visit[100][100];

void Find(int x,int y,char ch)
{
	
	if(visit[x][y])
		return ;
	visit[x][y]=1;
//	printf("(%d,%d)\n",x,y);
	if(maze[x+1][y]=='.')
		st.insert((x+1)*10+y);
	else if(maze[x+1][y]==ch)
		Find(x+1,y,ch);
	
	if(maze[x][y+1]=='.')
		st.insert((x)*10+y+1);
	else if(maze[x][y+1]==ch)
		Find(x,y+1,ch);
	
	if(maze[x-1][y]=='.')
		st.insert((x-1)*10+y);
	else if(maze[x-1][y]==ch)
		Find(x-1,y,ch);
	
	if(maze[x][y-1]=='.')
		st.insert(x*10+y-1);
	else if(maze[x][y-1]==ch)
		Find(x,y-1,ch);
}

void Delete(int x,int y,char ch)
{
	maze[x][y]='.';
	if(maze[x+1][y]==ch)
		Delete(x+1,y,ch);
	if(maze[x][y+1]==ch)
		Delete(x,y+1,ch);
	if(maze[x-1][y]==ch)
		Delete(x-1,y,ch);
	if(maze[x][y-1]==ch)
		Delete(x,y-1,ch);
}

void check()
{
	int i,j;
	printf("-------------------------------------------\n");
	for(i=1;i<=9;i++)
	{
		for(j=1;j<=9;j++)
		{
			printf("%c",maze[i][j]);
		}
		printf("\n");
	}
	printf("\n");
}

int main()
{
//	freopen("test.txt","r",stdin);
//	freopen("ou.txt","w",stdout);
	int ncase,n,m,i,j;
	scanf("%d",&ncase);
	for(int T=1;T<=ncase;T++)
	{
		for(i=1;i<=9;i++)
			scanf("%s",maze[i]+1);
		memset(visit,0,sizeof(visit));
		for(i=1;i<=9;i++)
		{
			for(j=1;j<=9;j++)
			{
				if(maze[i][j]=='o' && !visit[i][j])
				{
					st.clear();
					Find(i,j,'o');
					if(st.size()==0)
						Delete(i,j,'o');
				}
			}
		}
	//	check();
		memset(visit,0,sizeof(visit));
		for(i=1;i<=9;i++)
		{
			for(j=1;j<=9;j++)
			{
				if(maze[i][j]=='x' && !visit[i][j])
				{
					st.clear();
					Find(i,j,'x');
					if(st.size()==0)
						Delete(i,j,'x');
				}
			}
		}
	//	check();
		memset(visit,0,sizeof(visit));
		bool ok=false;
		for(i=1;i<=9 && !ok;i++)
		{
			for(j=1;j<=9 && !ok;j++)
			{
				if(maze[i][j]=='o' && !visit[i][j])
				{
					st.clear();
					Find(i,j,'o');
					if(st.size()==1)
						ok=true;
				}
			}
		}
		printf("Case #%d: %s\n",T,ok?"Can kill in one move!!!":"Can not kill in one move!!!");
	}
	return 0;
}


H.Sudoku

题意:将4*4的矩阵上空缺的位置填上数字,使其称为Sudoku。输出矩阵。

分析:把空缺的位置的坐标存起来,然后dfs暴力枚举空缺的位置上的数,判断填的数是否合法。能填满就说明方案可行。

代码:


#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;

struct node
{
	int x,y;
}s[100];
int cnt,getIt;

char maze[10][10];

bool ok(int x,int y,char ch)
{
	for(int i=1;i<=4;i++)
		if(maze[x][i]==ch)
			return false;
	for(int i=1;i<=4;i++)
		if(maze[i][y]==ch)
			return false;
	
	if(x<=2 && y<=2)
	{
		if(maze[1][1]==ch || maze[1][2]==ch || maze[2][1]==ch || maze[2][2]==ch)
			return false;
	}
	if(x>2 && y<=2)
	{
		if(maze[3][1]==ch || maze[3][2]==ch || maze[4][1]==ch || maze[4][2]==ch)
			return false;
	}
	if(x<=2 && y>2)
	{
		if(maze[1][3]==ch || maze[1][4]==ch || maze[2][3]==ch || maze[2][4]==ch)
			return false; 
	}
	if(x>2 && y>2)
	{
		if(maze[3][3]==ch || maze[3][4]==ch || maze[4][3]==ch || maze[4][4]==ch)
			return false;
	}
	return true;
}

void DFS(int cur)
{
	if(getIt)
		return ;
	if(cur>=cnt)
	{
		for(int i=1;i<=4;i++)
		{
			for(int j=1;j<=4;j++)
				putchar(maze[i][j]);
			putchar('\n');
		}
		getIt=1;
		return ;
	}
	int nx=s[cur].x,ny=s[cur].y;
	char buf=maze[nx][ny];
	for(char ch='1';ch<='4';ch++) if(ok(nx,ny,ch))
	{
		maze[nx][ny]=ch;
		DFS(cur+1);
		maze[nx][ny]=buf;
	}
}

int main()
{
//	freopen("data.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int ncase,i,j;
	scanf("%d",&ncase);
	for(int T=1;T<=ncase;T++)
	{
		getIt=cnt=0;
		for(i=1;i<=4;i++)
		{
			scanf("%s",maze[i]+1);
			for(j=1;j<=4;j++)
			{
				if(maze[i][j]=='*')
				{
					s[cnt].x=i;
					s[cnt++].y=j;
				}
			}
		}
		printf("Case #%d:\n",T);
		DFS(0);
	}
	return 0;
}


K.Game Rooms 

题意:有n层楼,现在每一层楼可以建两种设施里面的一种,已知每层楼里面分别想玩两种设施的人数,每个人的消耗为离他最近的楼层(楼层里面有他想玩的设施)的距离,现在问怎样建设施,使得总的消耗最小。

分析:定义dp[i][j][type],表示当前楼层为i,与之最近且不同的楼层为j(j<i),j建type设施。由当前楼层推到下一层的状态转移为:

 j               i i+1

$ * * * * * * *

①下一层也建type类型的设施,dp[i+1][j][type]=min(dp[i+1][j][type],dp[i][j][type]); //j~i+1的消耗暂时先不算

j                i i+1

$ * * * * * * $

②下一层建另外一种类型的设施:dp[i+1][i][type^1]=min(dp[i+1][i][type^1],dp[i][j][type]+v(j+1~i的消耗))

//j+1~i这一段的消耗=前一半到j层的消耗+后一半到i+1层的消耗

ps:消耗需要先预处理出来,O(1)查询。还有最后要把没有加完的部分加上。

特殊情况:********$,dp[i+1][i][type]=(前面所有*到$的消耗)

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E18+9;
const int maxn = 4007;

LL dp[2][maxn][2];
LL Prefix[maxn][2],Suffix[maxn][2],Sum[maxn][2];
LL a[maxn],b[maxn],n;
void Init(int n)
{
	int i,j,c;
	Prefix[0][0]=Prefix[0][1]=0;
	for(i=1;i<=n;i++)
	{
		Prefix[i][0]=Prefix[i-1][0]+a[i]*i;
		Prefix[i][1]=Prefix[i-1][1]+b[i]*i;
	}
	Suffix[n+1][0]=Suffix[n+1][1]=0;
	for(i=n,c=1;i>=1;i--,c++)
	{
		Suffix[i][0]=Suffix[i+1][0]+a[i]*c;
		Suffix[i][1]=Suffix[i+1][1]+b[i]*c;
	}
}
inline LL getPrefix(int type,int L,int R)
{
	if(L>R)	return 0;
	LL ret=Prefix[R][type]-Prefix[L-1][type];
	return	ret-(Sum[R][type]-Sum[L-1][type])*(L-1);
}
inline LL getSuffix(int type,int L,int R)
{
	if(L>R)	return 0;
	LL ret=Suffix[L][type]-Suffix[R+1][type];
	return ret-(Sum[R][type]-Sum[L-1][type])*(n-R); 
}

int main()
{
//	freopen("test.txt","r",stdin);
//	freopen("oyx.txt","w",stdout);
	int ncase,i,j,k;
	scanf("%d",&ncase);
	for(int T=1;T<=ncase;T++)
	{
		scanf("%d",&n);
		Sum[0][0]=Sum[0][1]=0;
		for(i=1;i<=n;i++)
		{
			scanf("%lld%lld",&a[i],&b[i]);
			Sum[i][0]=Sum[i-1][0]+a[i];
			Sum[i][1]=Sum[i-1][1]+b[i];
		}
		Init(n);
		int cur=0;
		for(j=1;j<=n;j++)
			dp[cur][j][0]=dp[cur][j][1]=INF;
		dp[cur][1][0]=b[1]; //现在的cur表示第2层 ,处理了第cur-1=1层
		dp[cur][1][1]=a[1];
		for(i=2;i<n;i++)
		{
			cur^=1;
			for(j=1;j<=i;j++)
				for(k=0;k<2;k++)
					dp[cur][j][k]=INF;
			dp[cur][i][0]=getSuffix(1,1,i);
			dp[cur][i][1]=getSuffix(0,1,i);
			for(j=1;j<i;j++)
			{
				for(k=0;k<2;k++)
				{
					LL v=dp[cur^1][j][k];
					if(v>=INF)
						continue ;
					dp[cur][j][k]=min(dp[cur][j][k],v);
					int mid=(j+1+i)>>1;
					LL temp=getPrefix(k,j+1,mid)+getSuffix(k,mid+1,i);
					dp[cur][i][k^1]=min(dp[cur][i][k^1],v+temp);
				}
			}
		}
		LL ans=INF,temp;
		for(j=1;j<n;j++)
		{
			temp=getPrefix(0,j+1,n);
    		ans=min(ans,dp[cur][j][0]+temp);
        	temp=getPrefix(1,j+1,n);
        	ans=min(ans,dp[cur][j][1]+temp);
		}
		printf("Case #%d: %lld\n",T,ans);
	} 
	return 0;
}

L.Huatuo's Medicine

题意:Huatuo有很多药和很多相同的瓶子,huatuo把药瓶子串成一条链,现在他只知道每种药的位置(不知道从哪头开始),问假如有n种药,这条链最短多长他能准确的取出他想要的药?

分析:2*n-1?

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;

int main()
{
	int ncase,x;
	scanf("%d",&ncase);
	for(int T=1;T<=ncase;T++)
	{
		scanf("%d",&x);
		printf("Case #%d: %d\n",T,x*2-1);
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值