2014北邮新生归来赛解题报告a-c

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">完全没状态的新生归来赛,虐的很惨</span>

A Hard Game

And it's now going to be a hard game.  N  piles of coins are put down on the ground, where each piles contains exactly  M  coins. Alice and Bob is coming to take coins again, and Alice starts first. The two players alternately choose a pile and take some number of coins(NOT zero, indeed) from the one he/she chooses. Your task is to judge who will win the game if both of them take the best strategy.

输入格式

The first line is the number of test cases  T(1T1000) . Each test case consists of only two integers  N  and  M(1N,M109) .

输出格式

Output 'Alice' if she wins, otherwise output 'Bob'.

输入样例

1
1 2

输出样例

Alice
一听名字就知道是最简单的签到题,一道很简单的简化nim,异或看为0不为0就行

这道题局势(2)时因为只有可能Alice拿走2个或者Alice1个Bob1个,胜者又是Alice,所以是拿到最后一颗的人胜,所以面对(0)的人就必定输了

nim博弈的共性:存在一个或多个状态起点和确定的状态转移路径,必败状态时只有一条或多条通向终局的必败路径,此时就算输,下一步只有必败状态(留给对手)就算必胜,必败态势中留给对手的总是非必败态势,若设必败态势是T,必胜态势S,那么必然有

1 T不能转移到T,只能转移到S,

2 S必然可以转移到T,

对于任意一组局面,(a1,a2,...,an)都存在2种可能 1 这组局面是T状态 2 这组局面是S状态

如何确定是否T态呢?

对于这组局面,若ak是最大值,那么当初始状态异或之和不为0时

使ak成为a1^a2^a3^a4...an(除去ak的异或结果)时,(ak-=(a1^a2^....an))

下一步的局势异或之和必定为0,此时不管对手怎么操作,异或之和都必定不为0,于是己方可以操作使其异或为0,

使异或为0的状态对应T态(0异或为0),异或不为0的状态对应S态,这个时候恰满足S态T态的状态转移.

而当初始异或为0时,ak就是a1^a2...an就没有办法改变了,也就是必败状态.

所以S态是异或之和不为0,T是异或之和为0

这个思路有点像数学归纳法

或者可以用sg函数,先来看单独一堆sg函数sg(x)=mex(sg(y)|y是x的后继节点).mex表示取到的非负整数集合没有出现后面那个集合中的最小数,我觉得sg函数就是用于路径压缩的并查集,那么sg(x)=0就是必败态,但这个游戏中存在的单独堆必不为必败态,

对于sg(x)=k.意味着它可以到达0-k-1任意某个状态,明显对这个游戏sg(x)=x,由Bouton’s Theorem,只要每个堆的异或之和为0就是必败态了


这道题简化在于每堆数目都相等,那么就奇数异或之和肯定不为0,也就是n%2!=0必胜,

/*
USER_ID: test#xuesu
PROBLEM: 396
SUBMISSION_TIME: 2014-07-12 13:35:16
*/
#include <iostream>
 
using namespace std;
 
int main()
{
    int t;
    cin >>t;
    while(t--){
        int n,m;
        cin>>n>>m;
        if(n%2==0)cout <<"Bob"<<endl;
        else cout << "Alice" << endl;
    }
    return 0;
}


时间限制 1000 ms  内存限制 65536 KB

题目描述

众所周知,如果一个正整数只能被1和自身整除,那么该数被称为素数。题目的任务很简单,就是判定一个数是否是一个素数。 只不过可能数的形式与正整数有一些不同,数的形式为a+bi,其中a、b为整数,且ii被定义为-1。如果a+bi能被分解为(a1+b1i)(a2+b2i)的形式,那么该数不是素数;否则,该数是素数。其中a1 、b1、 a2 、b2均为整数,且1,-1,0,i,-i不能作为被分解的因子。 注意,1,-1,0,i,-i均不为素数。

输入格式

输入包括若干组数据,每行包含2个数a、b,表示一个形如a+bi的数。a,b小于10000。

输出格式

对应于输入每行,如果输入的数为素数,则输出“YES”,否则输出“NO”。(不包括引号)

输入样例

-10 2
3 0

输出样例

NO
YES
这道题,好吧....连暴力都只是在最后半小时想到的....只是在思考:这会有什么性质,结果什么都没思考出来,到了最后半小时时间太急,果然没打出来,撞墙,撞墙

经验教训:没有使用计算机的思维,没有算法的思维,交给计算机跑就可以了.....即使算法复杂度有点高,只要能过就成,思路太过于零散了,没有整块的思路一开始想到了a*a+b*b=(a1*a1+b1*b1)(a2*a2+b2*b2)但是以为那是必然条件没有管它,但其实因为若n是平方和,那么一定能分解为唯一一对a,b>0使得a*a+b*b=n,也即实际上是充要条件,之后的问题是:漏看了a,,b<10000.不知道为什么就只认为范围是100,汗.,,,,,,,总之范围是10000时穷举不能,

查了查百度知道:

平方数的形式具有下列形式之一:16m,16m+1, 16m+4,16m+9

第一个数就先穷举,10*8复杂度,第二个数经过检查后二分,2a*a+2b*b-(a+b)*(a+b)是否为完全平方数,

不过怎么样还是不过,查看丁神代码(话说原来有小伙伴在csdn)发现原来是a*a+b*b=0或1 的时候没有处理,折腾了2小时....

思路:1 首先两重循环找小于sqrt(sq=(a*a+b*b))的平方和(分解因数)

2 然后不断除直到另一个因数为奇数,此时一定是一个奇数平方和,一个偶数平方和,%16余数一定是1,9,5,13之一,用这个条件筛一筛

3 使用2a*a+2b*b-(a+b)*(a+b)是否为完全平方数确认

#include<iostream>
#include <cmath>
using namespace std;
long long sqsum[20001];
int findequalorlessindex(int s,int e,long long aim){
    int mid=(s+e)/2;
    if(mid==s)return s;
    if(sqsum[mid]>aim)return findequalorlessindex(s,mid,aim);
    return findequalorlessindex(mid,e,aim);
}//二分搜索,设a>=b,则a*a+b*b<=(a+b)*(a+b)<=2a*a+2b*b
int main(){
    for(int i=0;i<20001;i++){
        sqsum[i]=i*i;
    }
    int a,b;
    while(cin>>a>>b){
        long long sq=a*a+b*b;
        bool fl=true;
        int sqroot2=sqrt(sq);
        for(int i=0;i<10000;i++){
            for(int j=i;j<10000;j++){
                    if(sqsum[i]+sqsum[j]>sqroot2)break;
                    if(sqsum[i]+sqsum[j]==0||sqsum[i]+sqsum[j]==1)continue;
                    if(sq%(sqsum[i]+sqsum[j])==0){
                        long long divisor=sq/(sqsum[i]+sqsum[j]);
                        while(divisor%2==0)divisor/=2;
                        int r=divisor%4;
                        if(r!=1)continue;
                        int indexofd=findequalorlessindex(1,20001,divisor);
                        int indexof2d=findequalorlessindex(1,20001,2*divisor);
                        for(int i=indexofd;i<=indexof2d;i++){
                                long long sqsumasubb=2*divisor-sqsum[i];
                                if(sqsumasubb<0)continue;
                                long long sqroot=sqrt(sqsumasubb);
                                if(sqroot*sqroot==sqsumasubb){
                                    fl=false;
                                    break;
                                }
                        }
                    }
            }
            if(!fl||sqsum[i]>=sqroot2)break;
        }
        if(sq==0||sq==1)fl=false;
        if(fl)cout<<"YES\n";
        else cout <<"NO\n";
    }
    return 0;
}
下面贴某神代码:
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>


using namespace std;


int main()
{
    long long a,b;
    while (~scanf("%lld%lld",&a,&b))
    {
        long long sp=a*a+b*b;
        bool judge=false;
        for (int i=2;i<=sqrt(sp);i++)
        {
            if (sp%i!=0) continue;
            int j=sp/i;
            while (i%2==0) i/=2;
            while (j%2==0) j/=2;
            if (i%4==1&&j%4==1)
            {
                judge=true;
                break;
            }
        }
        if (sp==1||sp==0) judge=true;
        if (judge) printf("NO\n");
        else printf("YES\n");


    }
}
证明4n+1型素数一定能分解为两平方数之和:

4n+1为奇数,所以如果为两平方数之和,则其一为偶数平方,另一为奇数平方。设x=2m,4m^2<=4n,即m^2<=n时,有4n-m^2+1为一个奇数的平方。设y=2p+1,y^2=4p^2+4p+1,x^2+y^2=4m^2+4p^2+4p+1=4(m^2+p^2+p)+1,∴,当n=m^2+p^2+p时,成立。


c:

时间限制 2000 ms  内存限制 65536 KB

题目描述

Krishna is a country with n cities, there are n-1 freeways between cities.If we don't consider direction of freeway, there is a unique path between every two cities. But unfortunately, some of freeways are directed. Now,there is a war between Krishna and Trots. In order to save valuable time, Moor, the High Command of Krishna, decided to transform freeways by change there's direction. So that soldiers in the central camp can reach any other cities from the central camp by freeways. The cost of transform one freeway is the same as the lenth of the freeway. In order to reduce expenditure, Moor has to choose a city as central camp to minimize the cost. But Moor is too busy, you should help him to find the position of central camp.

输入格式

There are multiply test case, and end of EOF Firstly give a integer n(0<n<100000).The following n-1 lines give 4 integers: t,u,v,w, whitch means that there are a freeway of length w between u and v(0=<w<=5000,0<u,v<100000). If t = 1, the freeway is directed, if t = 0, the freeway is undirected.

输出格式

Print two integers, the first one stands for the city whitch has central camp, the second one stands for the minimal cost to transform the freeway. If there exist many cities satify the condition, you should put central camp in the city with smallest id.

输入样例


   
     
5
1 1 2 3
1 2 3 1
0 2 4 5
1 5 4 4

输出样例

5 3

晕,原来这道题不可能有环,因为是n座城市,n-1条路而且还连通,人生啊,撞墙,没看清题意...我说用什么bellman啊...

这题真坑,城市的号不是连通的也有可能,不是从1开始的也有可能,这是说明人生有无穷多种可能吗?吗?

思路: dp,先得到从第一个城市出发的总路程(每条路径只需算一遍,如果是没有这个方向的就加0).然后从第一个城市出发到第二个城市(加2->1减1->2),得出所有点的最大可覆盖路程,用应当达到的总路程-最大可覆盖路程即可,时间复杂度n

#include <iostream>
#include <cstring>
using namespace std;
int first[100022];//没看到10^6,wa一次
int next[200024];
int to[200024];
int cost[200024];
bool vis[100022];
int n;
int maxn,minn;
int ans;
void dfs(int i ){
    int p=first[i];
    while(p!=-1){
        if(!vis[to[p]]){
            ans+=cost[p];
            vis[to[p]]=true;
            dfs(to[p]);
        }
        p=next[p];
    }
}
int dp[100022];
int maxcost;
int maxi;
void dfs2(int i){
    int p=first[i];
    if(dp[i]>maxcost){
        maxcost=dp[i];
        maxi=i;
    }
    while(p!=-1){
        if(!vis[to[p]]){
            dp[to[p]]=dp[i]-cost[p];
            if(p%2)dp[to[p]]+=cost[p-1];
            else dp[to[p]]+=cost[p+1];
            if(dp[to[p]]>maxcost){//神坑,这要是在后面从minn-maxn统计一遍就wa了,wa一次
                maxcost=dp[to[p]];
                maxi=to[p];
            }
            vis[to[p]]=true;
            dfs2(to[p]);
        }
        p=next[p];
    }
}
int topdfs(){
    memset(vis,0,sizeof(vis));
    ans=0;
    vis[minn]=true;
    dfs(minn);//从随便哪个点出发先求得一个dp基值
    dp[minn]=ans;
    memset(vis,0,sizeof(vis));
    vis[minn]=true;
    maxi=minn;
    maxcost=ans;
    dfs2(minn);//从这个点出发遍历,得到所有可覆盖的总路径长度
    return maxi;
}
int main(){
    ios::sync_with_stdio(false);
    while(cin>>n){
        memset(first,-1,sizeof(first));
        int d,u,v,w;
        int costsum=0;
        maxn=0;
        minn=0x3ffffff;
        for(int i=0;i<n-1;i++){
            cin>>d>>u>>v>>w;
            if(u>maxn)maxn=u;//神坑,不一定在1开始,n截止
            if(v>maxn)maxn=v;
            if(u<minn)minn=u;
            if(v<minn)minn=v;
            costsum+=w;
            to[2*i]=v;
            cost[2*i]=w;
            next[2*i]=first[u];
            first[u]=2*i;
            if(d){
                to[2*i+1]=u;
                cost[2*i+1]=0;
                next[2*i+1]=first[v];
                first[v]=2*i+1;
            }
            else {
                to[2*i+1]=u;
                cost[2*i+1]=w;
                next[2*i+1]=first[v];
                first[v]=2*i+1;
            }
        }
        topdfs();
        cout<<maxi<<" "<<costsum-maxcost<<"\n";
    }
    return 0;
}


你可能感兴趣的:(c)