2012 Multi-University Training Contest 7-1006 hdu4365 Palindrome graph

来源:互联网 发布:虚拟定位ios软件 编辑:程序博客网 时间:2024/06/06 00:25


简单的组合计数问题

坐标为(i,j)的数通过旋转能得到  (j,n-i-1),(n-i-1z),(n-j-1),(n-j-1,i)

通过旋转再家翻转后(i,j)能得到  (i,j),(n-i-1,j),(i,n-j-1),(n-i-1,n-j-1),(j,i),(j,n-i-1),(n-j-1,i),(n-j-1,n-i-1)

通过翻转我们知道需要染色的地方只有矩阵的左上角(其他地方的颜色只能与这一块儿对应相等)

通过上面的关系,(i,j)一定要与(j,i)染色相同。这样的话总共需要染色数就为   size*(size+1)/2  其中size为左上角矩阵的长度  size=n/2(向上取整)

接下来要做的就是排除那些已经染过色的数了。 某一个点已经被染色一定对应着左上角上一个相应的点被染色了,只要找到这些点对应的左上角的坐标再标记成染过色就OK了。找到标记坐标的方法很简单(只要找 n-i-1和i中小于size的数  和  n-j-1和j中小于size的数就可以)


实现的时候需要用快速幂取模,如果所有的数都用long long则会超时(需要读入时开挂)   如果都用int会WA(做乘法时数据会溢出) 所以要么全部开int在快速幂那儿用long logn保存中间结果要么直接开long long 再加输入挂


#include <iostream>#include <memory.h>#include <cstdio>using namespace std;bool visit[5002][5002];const int MOD = 100000007;long long getRes(int k,int tot){    if(tot==0) return 1;    if(tot==1) return k;    long long tmp = getRes(k,tot/2);    if(tot%2==0) return tmp*tmp%MOD;    else return tmp*tmp%MOD*k%MOD;}int input(){    int res=0;    char c=getchar();    while(c==' '||c=='\n') c=getchar();    while(true)    {        res+=c-'0';        c=getchar();        if(c<'0'||c>'9') break;        res*=10;    }    return res;}int main(){    int n,m,k,a,b,tmp,size,tot;    while(scanf("%d%d%d",&n,&m,&k)!=EOF)    {        size = n/2;        if(n%2) size++;        memset(visit,0,sizeof(visit));        tot = 0;        while(m--)        {            a = input();            b = input();            if(a>=size) a=n-1-a;            if(b>=size) b=n-1-b;            if(!visit[a][b])            {                tot++;                visit[a][b]=visit[b][a]=true;            }        }        tot = size*(size+1)/2-tot;        printf("%I64d\n",getRes(k,tot));    }    return 0;}



原创粉丝点击