1. 程式人生 > >第九屆福建省大學生程式設計競賽 部分題解

第九屆福建省大學生程式設計競賽 部分題解

這題是無符號的計算,但是有個坑就是我用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;
	}
}

這題如果把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]);
			}
		}
	}
}

題意:我有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));
	}
}

思路:求一個數學期望,這題就是個推公式題。


#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);
	}
}