2020 Multi-University Training Contest 7 07,09,10

AC:09,10

hdu6850 1007 Game 

很容易想到,如果先手到达最长点对之一,则必败。(后手可以走最长点对的另一点,使得先手无处可走)

对于一个游戏,把他转化为无向图。

先找出当前图中最长的边d。

然后把边长为d的所有边连接的点都删去(这些点称为必败点,到达即必败),然后这些点设为一层(称为必败层,即先手到这一层必败)

然后得到新的无向图。重复上述操作。

直到图只剩一个点,或者为空,最后的一个点设为一层。

显然这是一个分层图,只能由底层走向高层,且先跨层的人必败。

而且每层的距离都相同,说明每层最多只能移动一次。

即:若一个点x在某一层,他可以选在在这一层一定,则下一步的人必须跨层。

由此得到必胜策略:

对于点x,若其所在层点数不为1,则必胜,否则必败(必须跨层)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int N = 2000+7;
/*
int head[M],cnt=1;
void init(){cnt=1,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
struct node{
	ll x,y;
}p[N];
struct EDGE{
	int u,v;ll dis;
//	bool operator < (const EDGE &r)const{
//		return dis<r.dis;
//	}
}e[N*N];
bool cmp(EDGE a,EDGE b){
    return a.dis<b.dis;
}
ll dis(node a,node b)
{
	return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
int vs[N];
int main()
{
	//freopen("G.in","r",stdin);
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
			scanf("%lld%lld",&p[i].x,&p[i].y),vs[i]=0;
		int sz=0;
		for(int i=1;i<=n;i++)
			for(int j=1;j<i;j++)
				e[++sz]=EDGE{i,j,dis(p[i],p[j])};
		sort(e+1,e+1+sz,cmp);
		bool f=false;
		for(int i=sz;i>=1;i--)
		{
			int u=e[i].u,v=e[i].v;
			if(vs[u]||vs[v])continue;
			int j=i;
			vector<int>vv;
			while(j&&e[j].dis==e[i].dis)
			{
				if(vs[e[j].u]||vs[e[j].v])
				{
					j--;
					continue;
				}
				vv.pb(j);
				j--;
			}
			for(auto x:vv)
				vs[e[x].u]=vs[e[x].v]=1;
			i=j+1;
		}
		if(vs[1])puts("YES");
		else puts("NO");
	}
	return 0;
}

1009Increasing and Decreasing

思维水题

1010Jogging

显然若走到(i,i)则会无限游荡。则回到起点的概率为0.

若无法走,则必定留在原地。

现在问题是多个格子求留在起点的概率。

考虑上图,起点s,只在三个格子里游荡。若走无限步,则起点对结果不影响。

只考虑每个点由会由哪些情况到达即可:

对于点s:s停留会到达s,点1会到达s,共2种

对于点1:1停留在1,点2,s会到达1,共3种

对于点2:2停留在2,点1会到达2,共2种

则停留在点x的概率是总情况除到达点x的情况即可。

证明我也不会,但感性很容理解

而且题目给了样例,很容易猜出来

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;
/*
int head[M],cnt=1;
void init(){cnt=1,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
ll gcd(ll a,ll b)
{
    if(b==0)return a;
    return gcd(b,a%b);
}
bool flag=false;
int sm=0;
map<pair<ll,ll>,int>mp;
void dfs(ll x,ll y)
{
    //cout<<"--  "<<x<<" "<<y<<endl;
    if(flag||x==y)
    {
        flag=true;
        return ;
    }
    mp[{x,y}]=1;
    for(int i=-1;i<=1;i++)
        for(int j=-1;j<=1;j++)
        {
            ll xx=x+i,yy=y+j;
            if(gcd(xx,yy)>1)
            {
            //    cout<<"=-=-==-           "<<xx<<" - - "<<yy<<endl;
                sm++;
                if(mp.find({xx,yy})==mp.end())dfs(xx,yy);
            }
        }
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        ll x,y;
        scanf("%lld%lld",&x,&y);
        int fz=0;
        sm=0;flag=false;mp.clear();
        for(int i=-1;i<=1;i++)
            for(int j=-1;j<=1;j++)
                if(gcd(x+i,y+j)>1)fz++;
        dfs(x,y);
        if(flag)
        {
            puts("0/1");
            continue;
        }
        int c=gcd(fz,sm);
        printf("%d/%d\n",fz/c,sm/c);
    }
    return 0;
}
/*
3
18 16
18 6
18 8
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值