BUPT Spring Ranking Contest For 13 Round #1 Math & Games

比赛网址:http://vjudge.net/contest/view.action?cid=44588#overview

 

A题(HDU1850):最简单的NIM游戏,输出变形

解题思路:

记n1^n2^n3..^n[m]=x

显然若x=0,则该局势为奇异局势,必输。

如果把ni变成x^ni,则n1^n2^...^n[i-1]^n[i+1]^...^n[m]^x^ni=0,为奇异局势。显然如果ni>x^ni,如果能ni堆中拿走ni-x^ni张牌,则一定会获胜。

所以只用统计ni中比x^ni大于的个数,结果就是先拿者获胜的种数。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>

using namespace std;


int main ()
{
	int n,t,a[111];
	while(scanf("%d",&n) && n != 0)
	{
		int temp=0;
		for(int i=0;i<n;i++)
		{
			scanf("%d",&t);
			temp^=t;
			a[i]=t;
		}
		int ans=0;
		if(temp!=0)
		{

			for(int i=0;i<n;i++)
			{
				int k = 0;
                		for(int j=0;j<n;j++)
                   			 if(i!=j)
                        			k^=a[j];//只要能够取到K个,就能够根据对称原理获胜
                		if(k<=a[i])
                    			ans++;
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}

B题(HDU3032):NIM游戏的变形

解题思路:

用SG函数解答,对于所有的k,有SG(4k+1)=4k+1,SG(4k+2)=4k+2,SG(4k+3)=4k+4,SG(4k+4)=4k+3。(SG函数和博弈论的专栏,有兴趣可以研究一下http://blog.csdn.net/jxy859/article/details/6722660


#include<iostream>
#include<cstdlib>
#include<cstdio>

using namespace std;

int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        int ans=0,num;
        while(n--)
        {
            scanf("%d",&num);
            if(num%4==0)
		ans^=(num-1);
            else if(num%4==2||num%4==1)
		ans^=num;
            else
		ans^=(num+1);
        }
        if(ans!=0)
		puts("Alice");
        else
		puts("Bob");
    }
    return 0;
}

C题(UVA11889):数学题

解题思路:

数论,

A*B=C*gcd(A,B)

所以 B / gcd(A,B) = C / A

如果C / A不是整数,那么就无解。

不然B 一定是C / A 的整数倍。


#include<cstdio>
#include<iostream>

using namespace std;

int gcd(int a, int b)
{
	return b == 0 ? a : gcd(b, a % b);
}

int main(void)
{
	int T,a,b,c,d;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&a,&c);
		if(c%a)
			puts("NO SOLUTION");
		else
		{
			b=c/a;
			d=gcd(a,b);
			while(d!=1)//将c中不属于a的因数给b
			{
				b*=d;
				a/=d;
				d=gcd(a,b);
			}
			printf("%d\n",b);
		}
	}
	return 0;
}

D题(CodeForces 127C):数学题,我才不会告诉你我比赛的时候wa了7次还是没过(http://blog.csdn.net/hyogahyoga/article/details/8448886)

解题思路:

四个特判:

case 1: t1==t0 && t2!=t0=> y1=x1,y2=0

case 2: t2==t0 && t1!=t0=> y1=0,y2=x2

case 3: t1==t2 =>y1=x1,y2=x2

case 4: y1==0,方程解出y2=0,此时显然不对,所以此种情况仍需处理。

做法(暴力枚举):

枚举y1,然后t2可以解出来,在选最小的。


#include<iostream>
#include<cstring>
using namespace std;
long long t1,t2,x1,x2,t0,f1,f2;
long long cal(long long t1,long long y1,long long t2,long long y2)
{
    return t1*y1+t2*y2-t0*(y1+y2);
}
void solve(long long y1,long long y2)
{
    if(y2<0)y2=0;else if(y2>x2)y2=x2;//溢出
    if(y1==0 && y2==0)return;//WA

    if(t1*y1+t2*y2<t0*(y1+y2))return;//不满足t>=t0的条件
    if(cal(t1,y1,t2,y2)*(f1+f2)<cal(t1,f1,t2,f2)*(y1+y2)||(f1<0 && f2<0))
    {
        f1=y1;f2=y2;
    }
    else
    if(cal(t1,y1,t2,y2)*(f1+f2)==cal(t1,f1,t2,f2)*(y1+y2)&&y1+y2>f1+f2)
    {
        f1=y1;f2=y2;
    }
}
int main()
{
    long long y2;
    while(cin>>t1>>t2>>x1>>x2>>t0)
    {
        f1=-1,f2=-1;
        if(t1==t2)//case
        {
            f1=x1;f2=x2;
        }
        else if(t1==t0)//case
        {
            f1=x1;f2=0;
        }
        else if(t2==t0)//case
        {
            f1=0;f2=x2;
        }
        else
        for(long long y1=1;y1<=x1;y1++)
        {
            if(t0>t2)
            {
                y2=(t1*y1-t0*y1)/(t0-t2);
                solve(y1,y2);
            }
            else
            if(t0<t2)
            {
                y2=(t1*y1-t0*y1)%(t0-t2)==0?(t1*y1-t0*y1)/(t0-t2):1+(t1*y1-t0*y1)/(t0-t2);
                solve(y1,y2);
            }
        }
        //y1=0 case 4!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        if(t2>=t0)solve(0,x2);

        cout<<f1<<" "<<f2<<endl;
    }
    return 0;
}

E题:略坑的一些条件,数学题

解题思路:认真读题,然后根据数列公式求出通项就行


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>

using namespace std;

typedef long long ll;

int main()
{
	ll n;
	while(scanf("%lld",&n)&&n!=0)
	{
		n-=3;//将数列的下标按照1~n来计算,简单一些
		if(n<0)
			break;
 		printf("%lld\n",((2*n+3)*(n+2)*(n+1)/6-(n+2)/2)>>2);
 	}
 	return 0;
}

G题(HDU 4565):快速幂

解题思路:我的代码里没有用矩阵实现快速幂,题解来自(http://blog.csdn.net/xh_reventon/article/details/9970259)


#include<iostream>
#include<cstdio>
#include<cmath>

using namespace std;

typedef long long ll;

ll a,b,n,m;

ll q_pow2()
{
    ll ans1=1,ans2=0,t1=a,t2=1;
    ll t;
    while(n)
	{
        if(n&1)//1
		{
            t=ans1;
            ans1=(ans1*t1+ans2*t2*b)%m;
            ans2=(t*t2+ans2*t1)%m;
        }
        t=t1;//2
        t1=(t1*t1+t2*t2*b)%m;
        t2=2*t*t2%m;
        n>>=1;
    }
    return 2*ans1%m;
}
int main()
{
    while(~scanf("%lld%lld%lld%lld",&a,&b,&n,&m))
        printf("%lld\n",q_pow2());
    return 0;
}



你可能感兴趣的:(Math,博弈)