1. 回文图
(hui.pas/c/cpp)
【问题描述】
有一片透明玻璃,我们可以在上面涂色。涂色后,你可以对它做两种操作:
1.旋转,顺时针或逆时针旋转90度;
2.翻转,水平或垂直翻转180度;
不管进行多少次旋转或翻转,我们看到都是相同的图形,我们把这样的图形称为"回文图"。
下图是操作示例。请注意,图中并不是回文图。
现在给你一块n*n的方格状透明玻璃和k种颜色的油漆。请你给每个方格都涂上颜色,涂完后得到一幅回文图。但是这块玻璃上有m个方格事先已被涂上了颜色,你不能修改它们。
请问,总共能画出多少种不同的回文图?
【输入】
第一行,三个空格间隔的整数n,m,k
接下来m行,每行两个整数x和y,表示坐标为(x,y)的格子已被涂上了颜色(0<=x,y<n)。
【输出】
一行,一个整数,表示方案总数,结果可能很大,请输出Mod 100 000 007后的结果。
【输入输出样例1】
hui.in | hui.out |
3 0 2 | 8 |
【输入输出样例2】
4 2 3 1 1 3 1 | 3 |
【输入输出样例1说明】
【数据范围】
对于50%的数据: 0<n<=500,0<=m<=100,0<k<=100000
对于100%的数据: 0<n<=10000,0<=m<=2000,0<k<=1000000
题解:这道题算是一个简简单单的数学题吧(虽然我没有做出来。。。),只需要考虑方阵的一个1/8区域就可以了,设这个区域中有p个空格,有k种颜色,那么答案就是p^k
注意点是mod不是1e9+7而是1e8+7,然后就是给出的已涂色的方格得先把它变换到处理的那个1/8区域去,然后判重,再确定是否p--
P.S:(这是对我自己说的)要是不懂的话,可以去极乐净土上找原题解
code:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<map>
const int MAXN=10005;
const int mod=100000007;
typedef long long LL;
using namespace std;
int n,p,k,m,x,y,t;
bool vis[5005][5005];
LL mul(LL a,LL b,LL p){
LL ans=0;
for(LL i=1;i<=b;i<<=1,a=(a<<1)%p)
if(b&i) ans=(ans+a)%p;
return ans;
}
LL ksm(LL a,LL k,LL p){
LL ans=1;
while(k)
{
if(k&1) ans=mul(ans,a,p);
a=mul(a,a,p); k>>=1;
}
return ans;
}
inline void addpoint(int x,int y){
if(x>t) x=n-1-x;
if(y>t) y=n-1-y;
if(x<y) swap(x,y);
if(!vis[x][y])
vis[x][y]=1,p--;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
t=(n-1)>>1; p=(t+2)*(t+1)>>1;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
addpoint(x,y);
}
printf("%lld",ksm(k,p,mod));
}