2018西安电子科技大学第十六届“华为杯”大学生程序设计竞赛网络赛部分题题解


在写这篇题解的时候其实现场赛都打完了,不过因为最近事比较多,一直没有写这篇题解。今天碰巧有空,又补了一波题(虽说最后还是没AK),下面进入正文~

-------------------------------------------------------------------------------------------------------------------------------
A题

大水题,直接贴代码
#include<cstdio>
using namespace std;
int main()
{
	int n;
	int c;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&c);
		printf("%d\n",c*(c-1)/2);
		}
		return 0;
}

B题
水题,用gcd做即可
#include<cstdio>
using namespace std;
int gcd(int a,int b)
{
     int maxn,minn;
	 if(a>=b)
	 {
	     maxn=a;
		 minn=b;	
	 }
	 else
	 {
	     maxn=b;
		 minn=a;	
	 }
	 int t;
	 while(minn)
	 {
	    t=maxn%minn;
	    maxn=minn;
	    minn=t;
	 }
	 return maxn;	
}
int main()
{
	int a,b;
	while(scanf("%d%d",&a,&b)!=EOF)
	{
		printf("%d\n",gcd(a,b));
	}
	return 0;
 } 

C题
貌似使用前缀和做的,做了挺长时间了,有些忘了(逃)
#include<cstdio>
#include<algorithm>
using namespace std;
long long int a[100010];
long long int back[100010];
int main()
{
	long long int n,m;
	long long int sum;
	long long int index;
	while(scanf("%lld%lld",&n,&m)!=EOF)
	{
		sum=0;
		for(long long int i=0;i<n;i++)
		scanf("%lld",&a[i]);
		sort(a,a+n);
		if(n==1)
		printf("%lld\n",a[0]+m);
		  else
		 {	
		for(long long int i=n/2;i<n;i++)
		{
			sum+=a[i];	
			back[i]=sum;
		}
		long long int u=(n+1)/2;
        for(long long int i=n-1;i>=n/2;i--)
        {
        	if(u*a[i]-back[i]<=m)
        	{
        		index=i;
				m-=(u*a[i]-back[i]);
        		for(long long int j=n/2;j<=i;j++)
        		{
        			a[j]=a[i];
				}
				break;
			}
			u--;
		}
		long long int up=m/u;
		printf("%lld\n",a[index]+up);
	  }
    }
	return 0;
}

D题
找规律,但这个规律十分好找,打个表就出来了~
#include<cstdio>
using namespace std;
long long int f(long long int x)
{
	if(x<=100)
	return f(f(x+11));
	else
	return x-10;
}
int main()
{
	int n;
	long long int t;
	scanf("%d",&n);
	while(n--)
	{
		scanf("%lld",&t);
		if(t<=100)
		printf("91\n");
		else
		printf("%lld\n",t-10);
	}
	return 0;
 } 

E题
我用的是bfs,这道题能过,但在现场赛一加强数据就被虐了(还是菜)~
#include<cstdio>
#include<queue>
using namespace std;
typedef struct
{
	int s;
	int na;
	int nb;
}  node;
int bfs(int r)
{
	node n1;
	n1.s=0;
	n1.na=1;
	n1.nb=1;
	queue<node> q;
	q.push(n1);
	while(!q.empty())
	{
		node tem=q.front();
		q.pop();
		if(tem.nb==r)
		{
			return tem.s;
		}
		node n2;
		node n3;
		if(tem.na+tem.nb<=r)
		{
			n2.na=tem.na;
			n2.nb=tem.na+tem.nb;
			n2.s=tem.s+1;
			q.push(n2);
		}
		if(2*tem.nb<=r)
		{
		    n3.na=tem.nb;
			n3.nb=2*tem.nb;
			n3.s=tem.s+1;
			q.push(n3);	
		} 
	} 
}
int main()
{
	int n;
	int t;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&t);
		printf("%d\n",bfs(t));
	}
	return 0;
}

F题
赛后补出来的题,推一下递推式+矩阵快速幂,不过我的矩阵快速幂给写慢了,用了900多毫秒才过。。。
#include<cstdio>
#include<vector>
using namespace std;
typedef long long ll;
ll M=1e9+7;
typedef vector<ll> vec;
typedef vector<vec> mat;
mat mul(mat &A,mat &B)
{
	int l1=A.size();
	int l2=B[0].size();
	int l3=B.size();
	mat C(A.size(),vec(B[0].size()));
	for(int i=0;i<l1;i++)
	{
		for(int k=0;k<l3;k++)
		{
			for(int j=0;j<l2;j++)
			{
				C[i][j]=(C[i][j]+A[i][k]*B[k][j])%M;
			}
		}
	}
	return C;
}
mat powmod(mat A,ll n)
{
	int l4=A.size();
	mat B(l4, vec(l4));
    for(int i=0;i<l4;i++)
    {
    	B[i][i]=1;
	}
	while(n>0)
	{
		if(n&1)
		B=mul(B,A);
		A=mul(A,A);
		n>>=1; 
	}
	return B;
}
int main()
{
	ll n;
	while(scanf("%lld",&n)!=EOF)
	{
		mat A(3,vec(3));
		A[0][0]=1;
		A[0][1]=1;
		A[0][2]=0;
		A[1][0]=-1;
		A[1][1]=0;
		A[1][2]=1;
		A[2][0]=1;
		A[2][1]=1;
		A[2][2]=1;
		A=powmod(A,n);
		ll t1;
		t1=(A[0][0]+A[0][2])%M;
		ll t2;
		t2=(A[1][0]+A[1][2])%M;
		ll ans;
		ans=(t1+t2)%M;
		if(ans<0)
		ans+=M;
		printf("%lld\n",ans);
	}
	return 0;
}

G题
一道八数码问题,bfs+康拓展开来压缩状态即可~
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
char biao[10]="012345678";
int bb[]={0,1,2,3,4,5,6,7,8};
char a[10];
int sx,sy;
int st;
int vis[370000];
int f[10] = {1,1,2,6,24,120,720,5040,40320,362880};
typedef struct
{
	char c[10];
	int cc[10];
	int s;
	int z;
	int ct;
} node;
int Canton(int s[])  
{  
    int sun = 0, tmp;  
    for (int i = 0; i < 9; i++)  
    {  
        tmp = 0;  
        for (int j = i + 1; j < 9; j++)  
            if (s[j] < s[i]) tmp++;  
        sun += (tmp * f[9 - i - 1]);  
    }  
    return sun + 1;  
}  
int bfs()
{
	queue<node> q;
	node n1;
	int dx[4]={1,-1,3,-3};
	n1.s=0;
	n1.z=st;
	strcpy(n1.c,a);
	for(int i=0;i<9;i++)
	n1.cc[i]=n1.c[i]-'0';
	n1.ct=Canton(n1.cc);
	vis[n1.ct]=1;
	q.push(n1);
	while(!q.empty())
	{
		node tem=q.front();
		q.pop();
	    if(strcmp(tem.c,biao)==0)
	    return tem.s;
//        if(Canton(tem.cc)==Canton(bb))
//        return tem.s;
		 for(int i=0;i<4;i++)
	     {
	     	  if(tem.z%3==0&&i==1)
			   continue;
			  if(tem.z%3==2&&i==0)
			  continue; 
			   node n2;
	     	  n2.s=tem.s+1;
			  int tx=tem.z+dx[i];
	     	 n2.z=tx;
			 if(tx>=0&&tx<=8)
			 {
				 strcpy(n2.c,tem.c);
				 char t=n2.c[tx];
				 n2.c[tx]=n2.c[tem.z];
				 n2.c[tem.z]=t;
				 for(int i=0;i<9;i++)
	             n2.cc[i]=n2.c[i]-'0';
				 int tt=Canton(n2.cc);
				 if(vis[tt]==0)
				 {
				   q.push(n2);
				   vis[tt]=1;
			     }
			 }
		 }
	}
	return -1;
}
int main()
{
	int n;
	int t;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int u=0;
		memset(vis,0,sizeof(vis));
		for(int j=1;j<=3;j++)
		{
			for(int k=1;k<=3;k++)
			{
			  scanf("%d",&t);
		       a[u]=t+'0';	  
			  if(t==0)
			   st=u;
			   u++;
		    }
		}
		a[9]='\0';
		int res=bfs();
		if(res!=-1)
		printf("%d\n",res);
		else
		{
		  printf("cannot\n");
	    }
    }
    return 0;
}

H题
其实这是一道贪心题(证明的话不太容易),不过仔细想一想其实可以想出来~

就是排序,相邻的一定斜率最小,见代码:
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#include<cstdlib>
#include<queue> 
#include<cstring>
using namespace std;
typedef struct
{
	int w;
	int no;
}  P;
P p[1000010];
bool cmp(P a,P b)
{
	return a.w<b.w;
}
int main() 
{
	int n;
	int t; 
	while(scanf("%d",&n)!=EOF)
{
	for(int i=0;i<n;i++)
	{
		scanf("%d",&t);
		p[i].w=t;
		p[i].no=i;
	}
	sort(p,p+n,cmp);
	double tem;
	double minn=2e9;
	for(int i=1;i<n;i++)
	{
		tem=fabs((double)(p[i].w-p[i-1].w)/(p[i].no-p[i-1].no));
		minn=min(tem,minn);
	}
	printf("%.2lf\n",minn);
}
	return 0;
}

I题(不会,待补。。。)

J题
赛后写出来的题,用了一个Markov过程(其实我之前不知道。。。),简单地说就是未来的状态只与现在有关,而与过去无关。仔细想一想,这题确实是这样的。然后就是推个期望的递推式。。。详见代码:
#include<cstdio>
#include<cmath>
using namespace std;
double e[510];
int t;
double solve(int n)
{
	double sum=0;
	for(int i=0;i<=500;i++)
	e[i]=0;
	e[0]=0;
	for(int i=1;i<=n;i++)
	{
       e[i]=(double)n/i;
       for(int j=1;j<=i;j++)
       {
           e[i]+=(1.0/i)*e[i%j];
       }
       sum+=e[i];
	}
	return sum/n+1;
}
int main()
{
    while(scanf("%d",&t)!=EOF)
    printf("%.2lf\n",solve(t));
    return 0;
}
最后附上xdoj上的题解(思路): http://acm.xidian.edu.cn/download/2018-online-unofficial-editorial.pdf

猜你喜欢

转载自blog.csdn.net/star_moon0309/article/details/80108937