2018,5.19 T3 CF57E

象棋
【问题描述】
小美很喜欢下象棋。
而且她特别喜欢象棋中的马。
她觉得马的跳跃方式很独特。(以日字格的方式跳跃)
小芳给了小美一张很大的棋盘,这个棋盘是一个无穷的笛卡尔坐标。
一开始 time=0 的时候,马在原点。每个时刻马都跳一步。
可是这个坐标图有点残缺,有几个点是不能跳到的。
然后小美很好奇在 time=[0,K] 中,马能跳到多少个不同的格子。
【输入格式】
从文件 chess.in 中读入数据。
第一行两个数 K,n 表示时间上限和残缺的点的数量。
接下来 n 行,每行一个坐标 xi,yi 表示一个残缺点的坐标。
【输出格式】
输出到文件 chess.out 中。
第一行输出一个数字表示答案。由于这个数字会很大,你需要输出他
模 1000000007。
【样例输入】
1 0
【样例输出】
9
【样例输入】
2 7
-1 2
1 2
2 1
2 -1
1 -2
-1 -2
-2 -1
【样例输出】
9
【数据规模】
对于 30% 的数据 K ≤ 500

对于 100% 的数据 0 ≤ K ≤ 10^18 ,0 ≤ n ≤ 440,|xi| ≤ 10,|yi| ≤ 10

——————————————————————————————————————————

此题很假!!!

30%要打BFS,用DFS会T,剪枝会wa

100%先随便造一组数据,k大一点,一两百,然后BFS,记录每次拓展了几个,可以就找规律啦,

当k较大时,每次增量趋于稳定,是28,也就是说加入cnt[i]=100,cnt[i+1]=100+28*1,cnt[i+2]=100+28*2……

正解:k>500是,先跑一边k=500,之后可以直接用等差数列加速

#include <algorithm>
#include <cstdio>
#include <queue>
using namespace std;
#define int long long
const int P=1000000007;
int mp[2007][2007];
int mx[8]={1,2,2,1,-1,-2,-2,-1},
	my[8]={2,1,-1,-2,-2,-1,1,2};
queue<int> qx,qy;
int n,k,ans,cnt[1000],step;
void bfs(int x,int y) {
	mp[x][y]=1;
	qx.push(x);qy.push(y);
	while (!qx.empty()) {
		int x=qx.front(),y=qy.front();qx.pop();qy.pop();
		ans++;cnt[mp[x][y]]++;
		if (mp[x][y]==step+1) continue;
		for (int i=0;i<8;i++) {
			int xx=x+mx[i],yy=y+my[i];
			if (mp[xx][yy]) continue;
			mp[xx][yy]=mp[x][y]+1,qx.push(xx),qy.push(yy);
		}
	}
}
signed main() {
	freopen("chess.in","r",stdin);
	freopen("chess.out","w",stdout);
	scanf("%lld%lld",&k,&n);
	for (int i=1,x,y;i<=n;i++) {
		scanf("%lld%lld",&x,&y);
		x+=1000;y+=1000;
		mp[x][y]=1;
	}
	step=min(k,(int)500);
	bfs(1000,1000);
	if (k<=500ll) return printf("%lld\n",ans%P),0;
	int zz=cnt[501]-cnt[500];k=(k-500ll)%P;
	printf("%lld\n",(ans+cnt[501]*k+(k*(k+1)/2%P*zz)%P)%P);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41893580/article/details/80382399
今日推荐