第九届福建省大学生程序设计竞赛 部分题解

A题:FZU 2294

这题是无符号的计算,但是有个坑就是我用printf输出一直wa,用cout输出就AC。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
using namespace std;
long long unsigned mod; 
map<string,long long unsigned>m;
void init()
{
	mod=1;
	for(int i=1;i<=47;i++)
	mod*=2;
}
int main()
{
	long long unsigned num1 ;
	string a,b,op;
	init();
	while(cin>>op)
	{
		if(op=="def")
		{
			cin>>a>>num1;
			m[a]=(num1+mod)%mod;
		}
		else if(op=="add")
		{
			cin>>a>>b;
			m[a]=(m[a]+m[b])%mod;
		}
		else if(op=="sub")
		{
			cin>>a>>b;
			m[a]=(m[a]-m[b])%mod;
		}
		else if(op=="mul")
		{
			cin>>a>>b;
			m[a]=(m[a]*m[b])%mod;
		}
		else if(op=="div")
		{
			cin>>a>>b;
			m[a]=m[a]/m[b];
		}
		else
		{
			cin>>a>>b;
			m[a]=m[a]%m[b];
		}
		cout<<a<<" = "<<m[a]<<endl;
	}
}

D题:FZU 2297

这题如果把M改成质数,就是个水题n了,可惜不是,就成了一个好题,为了不丢失精度,每次D操作都得把之前所有的有效M次操作的数相乘,这样才能避免除法,这样时间复杂度是n^2,不过区间问题可用线段树优化成nlogn。单点更新,求最大的区间之积。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5;
long long mod,y,value;
long long tree[4*maxn];
void update(int L,int R,int o,int k)
{
	if(L==R)
	{
		tree[o]=value;
		return;
	}
	int m=(L+R)/2;
	if(k<=m)
	update(L,m,o*2,k);
	else
	update(m+1,R,o*2+1,k);
	tree[o]=tree[o*2]*tree[o*2+1]%mod;
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int q,i;
		char op[2];
		scanf("%d%lld",&q,&mod);
		for(i=1;i<maxn*4;i++)
		tree[i]=1;
		for(i=1;i<=q;i++)
		{
			scanf("%s%lld",op,&y);
			if(op[0]=='M')
			{
				value=y;
				update(1,maxn,1,i);
				printf("%lld\n",tree[1]);
			}
			else
			{
				value=1;
				update(1,maxn,1,y);
				printf("%lld\n",tree[1]);
			}
		}
	}
}

H题:FZU 2301

题意:我有n次攻击次数,敌人有m滴血,一次攻击扣一滴血,但是我有1/2的概率攻击的不是这个敌人,求我把他杀死的概率,举个例子,n=2,m=1,假设1为攻击到敌人,0每攻击到敌人,那么有效攻击种类为10,01,11,总攻击种类有四种,那么杀死的概率就是3/4(除法用逆元)

思路:很明显我至少有m次攻击到敌人才能杀死他,那么有效攻击种类为C(m,n)+C(m+1,n)+..+C(n,n),总攻击种类有2^n,由于n最大取1000,可以提前把2^1到2^1000次方的逆元打表,也要先把∑C(i,n)(i=m,m+1,..n)的杨辉三角后缀和打表。

#include<cstdio>
#include<cstring>
using namespace std;
const int mod=1e9+7;
const int maxn=1e3+10;
long long a[maxn],b[maxn][maxn];
long long pows(long long x,int y)
{
	long long res=1;
	while(y)
	{
		if(y%2==1)
		res=res*x%mod;
		x=x*x%mod;
		y/=2;
	}
	return res;
}
void init()
{
	long long t=2;
	for(int i=1;i<maxn;i++)
	{
		a[i]=pows(t,mod-2);
		t=t*2%mod;
	}	
	b[0][1]=b[1][0]=b[1][1]=1;
	for(int i=2;i<maxn;i++)
	{
		b[i][0]=b[i][i]=1;
		for(int j=1;j<i;j++)
		b[i][j]=(b[i-1][j-1]+b[i-1][j])%mod;
	}
	for(int i=1;i<maxn;i++)
	{
		for(int j=i-1;j>=0;j--)
		{
			b[i][j]=(b[i][j]+b[i][j+1])%mod;	
		}	
	}


}
int main()
{
	int T;
	init();
	scanf("%d",&T);
	while(T--)
	{
		int n,m;
		scanf("%d%d",&n,&m);
		if(m==0)
		{
			printf("1\n");	
		}
		else if(n<m)
		printf("0\n");	
		else
		printf("%lld\n",b[n][m]*a[n]%mod);
	}
}

I题用区间DP记忆化搜索,算了算复杂度为200^3竟然超时了。。。

思路:设d[ i ][ j ][ p ]为区间 i 到 j 的序列,再划分p块的最小值,那么

d[ i ][ j ][ p ]=min(sum(i, k)+dfs(k+1, j ,p-1 )),虽然超时, 但是还是奉献出代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=99999999;
int d[201][201][201],a[201],sum[201];
int n,k;
int pow(int t)
{
	return t*t;
}
void init()
{
	sum[0]=0;
	memset(d,0,sizeof(d));
}
int dfs(int i,int j,int remain)
{
	if(j-i+1<remain)
	return inf;
	if(remain==1)
	return d[i][j][remain]=pow((sum[j]-sum[i-1]));
	if(d[i][j][remain]!=0)
	return d[i][j][remain];
	int ans=inf;	
	if(i==1&&j==n)//特别注意这个序列是个环,起点和终点连在一起的 
	{
		for(int k=2;k<n;k++)
		{
			for(int p=k;p<n;p++)
			{
				int t=dfs(k,p,remain-1)+pow(sum[k-1]+sum[n]-sum[p]);
				ans=min(ans,t);
			}
		}
	}
	for(int k=i;k<j;k++)
	{
		int t=pow(sum[k]-sum[i-1])+dfs(k+1,j,remain-1);
		ans=min(ans,t);
	}	
	for(int k=i+1;k<=j;k++)
	{
		int t=dfs(i,k-1,remain-1)+pow(sum[j]-sum[k-1]);
		ans=min(ans,t);
	}
	return d[i][j][remain]=ans;
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int i; 
		scanf("%d%d",&n,&k);
		init();
		for(i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			sum[i]=sum[i-1]+a[i];	
		}
		printf("%d\n",dfs(1,n,k));
	}
}

J题:FZU 2303

思路:求一个数学期望,这题就是个推公式题。


#include<stdio.h>
const int mod=1e9+7;
const int maxn=1e6+20;
long long a[maxn];
long long pows(long long x,int y)
{
	long long res=1;
	while(y)
	{
		if(y&1)
		res=res*x%mod;
		x=x*x%mod;
		y=(y>>1); 
	}
	return res;
}
void init()
{
	int i;
	for(i=1;i<maxn;i++)
	a[i]=pows(i,mod-2);
}
int main()
{
	int T;
	init();
	scanf("%d",&T);
	while(T--)
	{
		 int n,m;
		 long long ans,L=1;
		 scanf("%d%d",&n,&m);
		 if(n<=m)
		 {
		 	printf("%d\n",n);
		 	continue;
		 }
		 ans=(L*m*(n+1)%mod)*a[m+1]%mod;
		 printf("%lld\n",ans);
	}
}


猜你喜欢

转载自blog.csdn.net/ccsu_cat/article/details/80746043