zoukankan      html  css  js  c++  java
  • [Noip2018]填数游戏

    传送门

    Description

    耳熟能详,就不多说了

    Solution

    对于一个不会推式子的蒟蒻,如何在考场优雅地通过此题

    1. 手玩样例,发现对于 (n=1)(ans=2^m) 。对于 (n=2)(ans=4 imes 3^{m-1}) 。或者干脆打出 (n,mle 3) 的表

    2. 肉眼观察法,发现似乎有 (f(n,m+1)=3f(n,m)),但这并不是正确的,但如果你仅仅是这么认为了,你仍然能够获得很多分数

    3. 想结论,都是特别特别显然的那种:

    • (f(n,m)=f(m,n)) ,因而只要考虑 (nle m) 的情况

    • 因为每步向右或向下,所以可按照步骤,把图分成一条条从左下到右上的斜线,对于单个格子进行考虑,发现每条斜线上的数单调不增(所以呢,你就可以通过枚举每条斜线在哪个位置开始变为(0)就可以了,简单打表)

    • 为了检验图的正确性,我们还需要发掘合法填数方式的更多性质:

      考虑怎样造成不合法,存在两条路径,它们在某个位置不合法了,那么它们之前路径对应的01串相同,且上一个位置相同,在不合法的这一步中,大的路径走了 (0) ,小的路径走了 (1)

      这启发我们,对于一张合法的图,如果某个点,存在两条到达它的路径对应相同的01串,那么它的后继相同,我们令这样的点叫(A)点,一个点是(A)点当且仅当它的前驱中有A点或者它的前驱的数相同

    1. 有了这么多的性质,我们发现其实可以打表拿很多分了,于是开始愉快地搜索,按照斜线一条条地搜,边搜边更新当前图的点中(A)类的点,同时,每条斜线上只有 (0)(1) 的交界处可能导致不合法,判断一下它的上一个点是否是(A)类点就可以了
    2. 打出表了,发现结论 (f(n,m+1)=3f(n,m),m>n) !于是就很开心地过了
    3. 这个搜索是真的快,极限数据 (n=8,m=9) 都能在 (0.6s) 内过去,所以就连表都懒得打了,直接暴力就行了

    Code 

    #include<bits/stdc++.h>
    #define ll long long
    #define db double
    #define reg register
    using namespace std;
    #define dbg1(x) cerr<<#x<<'='<<(x)<<' '
    #define dbg2(x) cerr<<#x<<'='<<(x)<<'
    '
    #define dbg3(x) cerr<<#x<<'
    '
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    const int P=1e9+7;
    int Add(int x,int y){return (x+y)%P;}
    int Mul(int x,int y){return (1ll*x*y)%P;}
    int fp(int x,int y){int r=1;if(y>0)for(;y;y>>=1,x=Mul(x,x))if(y&1)r=Mul(r,x);return r;}
    int n,m;ll ans=0;
    int Nm[20],X[20][20],Y[20][20];
    bool mk[10][10],mp[10][10];
    inline void getmk(int now)
    {
    	int i,j;
    	for(i=X[now][1],j=Y[now][1];i&&j<=m;--i,++j)
    		if(i>1&&j>1)mk[i][j]=(mk[i-1][j]|mk[i][j-1]|(mp[i][j-1]==mp[i-1][j]));
    }
    void dfs(int now)
    {
    	int i,j,p=Nm[now];getmk(now-1);
    	for(i=0;i<=p;++i)
    	{
    		if(i)mp[X[now][i]][Y[now][i]]=true;
    		if((i==0||i==p)||(i>0&&i<p&&!mk[X[now][i]-1][Y[now][i]]))
    			if(now+1==n+m)++ans;else dfs(now+1);
    	}
    	for(i=1;i<=p;++i)mp[X[now][i]][Y[now][i]]=0;
    }
    int main()
    {
    	freopen("game.in","r",stdin);
    	freopen("game.out","w",stdout);
    	n=read();m=read();
    	if(n>m)swap(n,m);
    	if(n==1)return 0*printf("%d
    ",fp(2,m));
    	int c=max(0,min(m-n,m-n-1));m-=c;
    	reg int i,j;
    	for(i=1;i<=n;++i)Nm[i]=i;
    	for(i=n+1;i<m;++i)Nm[i]=n;
    	for(i=m;i<n+m;++i)Nm[i]=n+m-i;
    	for(i=1;i<=n;++i)X[i][1]=i,Y[i][1]=1;
    	for(i=n+1;i<n+m;++i)X[i][1]=n,Y[i][1]=i-n+1;
    	for(i=1;i<n+m;++i)for(j=2;j<=Nm[i];++j)X[i][j]=X[i][j-1]-1,Y[i][j]=Y[i][j-1]+1;
    	dfs(1);printf("%lld
    ",Mul(ans,fp(3,c)));
    }
    


    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    第3章 结束会话端点(EndSession Point)
    第2章 授权端点(Authorize Endpoint)
    第1章 发现端点(Discovery Endpoint)
    欢迎使用IdentityModel文档!- IdentityModel 中文文档(v1.0.0)
    IdentityModel 中文文档(v1.0.0) 目录
    第66章 视频
    第65章 博客帖子
    第64章 学习
    Jenkins Ant 自动编译部署测试环境
    jenkins+jmeter+ant自动化接口测试集成
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/11808887.html
Copyright © 2011-2022 走看看