[Luogu P3277] [BZOJ 2335] [SCOI2011]飞镖

洛谷传送门
BZOJ传送门

题目描述

飞镖是在欧洲颇为流行的一项运动。它的镖盘上分为 20 20 20个扇形区域,分别标有 1 1 1 20 20 20的分值,每个区域中有单倍、双倍和三倍的区域,打中对应的区域会得到分值乘以倍数所对应的分数。

例如打中 18 18 18分里面的三倍区域,就会得到 54 54 54分。

另外,在镖盘的中央,还有”小红心“和”大红心“,分别是 25 25 25分和 50 50 50分。

通常的飞镖规则还有一条,那就是在最后一镖的时候,必须以双倍结束战斗,才算获胜。也就是说,当还剩12分的时候,必须打中双倍的 6 6 6才算赢,而打中单倍的 12 12 12或者三倍的 4 4 4则不算。

特别的,”大红心“也算双倍(双倍的 25 25 25)。在这样的规则下, 3 3 3镖能解决的最多分数是 170 170 170分(两个三倍的 20 20 20,最后用大红心结束)。

现在,lxhgww把原来的 1 1 1 20 20 20分的分值变为了 1 1 1 K K K分,同时把小红心的分数变为了 M M M分(大红心是其双倍),现在lxhgww想知道能否在 3 3 3镖内(可以不一定用满 3 3 3镖)解决 X X X分。同样的,最后一镖必须是双倍(包括大红心)。

输入输出格式

输入格式:

输入的第一行是一个整数 T T T,包括了 T T T组数据。

第二行是 5 5 5个整数, A 1 , B 1 , C 1 , D 1 , K 1 A_1,B_1,C_1,D_1,K_1 A1,B1,C1,D1,K1,表示第一组数据的镖盘是从 1 1 1 K 1 K_1 K1分的,随后数据的镖盘由公式 K i = ( A 1 K i − 1 2 + B 1 K i − 1 + C 1 ) m o d D 1 + 20 K_i=(A_1K^2_{i-1}+B_1K_{i-1}+C_1)mod D_1 + 20 Ki=(A1Ki12+B1Ki1+C1)modD1+20决定,其中第 i ( 1 &lt; i ≤ T ) i(1&lt;i\le T) i(1<iT)组数据的镖盘是从 1 1 1 K i K_i Ki分的。

第三行是 5 5 5个整数, A 2 , B 2 , C 2 , D 2 , M 1 A_2,B_2,C_2,D_2,M_1 A2,B2,C2,D2,M1,表示第一组数据的小红心 M 1 M_1 M1分的,随后数据的镖盘由公式 M i = ( A 2 M i − 1 2 + B 2 M i − 1 + C 2 ) m o d D 2 + 20 M_i=(A_2M^2_{i-1}+B_2M_{i-1}+C_2)mod D_2 + 20 Mi=(A2Mi12+B2Mi1+C2)modD2+20决定,其中第 i ( 1 &lt; i ≤ T ) i(1&lt;i\le T) i(1<iT)组数据的小红心是 M i M_i Mi分。

第四行是 5 5 5个整数, A 3 , B 3 , C 3 , D 3 , X 1 A_3,B_3,C_3,D_3,X_1 A3,B3,C3,D3,X1,表示第一组数据需要解决的分数是 X 1 X_1 X1分的,随后数据的镖盘由公式 X i = ( A 3 X i − 1 2 + B 3 X i − 1 + C 3 ) m o d D 3 + 20 X_i=(A_3X^2_{i-1}+B_3X_{i-1}+C_3)mod D_3 + 20 Xi=(A3Xi12+B3Xi1+C3)modD3+20决定,其中第 i ( 1 &lt; i ≤ T ) i(1&lt;i\le T) i(1<iT)组数据需要解决的分数是 X i X_i Xi分。

输出格式:

一行,包括一个数字,表示这 T T T组数据中,能够被解决的数据数目。

输入输出样例

输入样例#1:
5
1 2 2 10 20
1 3 2 15 25
2 2 5 200 170
输出样例#1:
4

说明

对于30%的数据,保证 1 ≤ T ≤ 20 , 20 ≤ K 1 , M 1 , X 1 , D 1 , D 2 , D 3 ≤ 1000 1\le T\le 20,20\le K_1,M_1,X_1,D_1,D_2,D_3\le 1000 1T20,20K1,M1,X1,D1,D2,D31000

对于100%的数据,保证 1 ≤ T ≤ 1 0 6 , 20 ≤ K 1 , M 1 , X 1 , D 1 , D 2 , D 3 ≤ 1 0 9 1\le T\le 10^6,20\le K_1,M_1,X_1,D_1,D_2,D_3\le 10^9 1T106,20K1,M1,X1,D1,D2,D3109

对于所有的数据,保证 0 ≤ A 1 , B 1 , A 2 , B 2 , C 2 , A 3 , B 3 , C 3 ≤ 1 0 9 0\le A_1,B_1,A_2,B_2,C_2,A_3,B_3,C_3 \le 10^9 0A1,B1,A2,B2,C2,A3,B3,C3109

解题分析

恶心的特判题。

首先有一个结论:在 5 K 5K 5K之内除了 1 1 1 5 K − 1 5K-1 5K1都可以用 2 a + 3 b 2a+3b 2a+3b这种形式凑出来, 证明倒着来凑, 发现是每 5 5 5个一个循环就行了。

M M M表示小红心, i i i表示其他位置的 1 ∼ 3 1\sim 3 13倍区域。

先考虑没有红心的情况:

  1. i
  2. i,i
  3. i,i,i

前两个比较好判, 最后那个由于 K &gt; 20 K&gt;20 K>20, 如果 X &lt; 2 K X&lt;2K X<2K显然是有解的, X &gt; 2 K X&gt;2K X>2K的情况先搞一个 2 K 2K 2K出来, 剩下的尝试用 2 a + 3 b 2a+3b 2a+3b 3 a + 3 b 3a+3b 3a+3b的形式凑就好了。

然后是有红心的情况:

  1. M,i,i

  2. 2M,i,i

  3. M,M,i

  4. 2M,M,i

  5. 2M,2M,i

  6. i,i,2M

  7. i,M,2M

  8. i,2M,2M

  9. M,M,2M

  10. M,2M,2M

  11. 2M,2M,2M

  12. M,i

  13. M,2M

  14. i,2M

  15. 2M

这么直接讨论太麻烦了, 分成几类:

第一类: 4, 5

第二类: 6 , 7, 8, 15

第三类: 9

第四类: 10, 11, 17

第五类: 12, 13, 14, 16, 17

然后大力判就好了…

代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ll long long
ll K, M, X, A[3], B[3], C[3], D[3];
int T, ans;
IN bool c1(R ll val)
{
	if (val <= 1 || val == 5 * K - 1) return false;
	if (val > 5 * K) return false;
	return true;
}
IN bool c2(R ll val)
{
	if (val <= 0 || val > 2 * K) return false;
	return val % 2 == 0;
}
IN bool c3(R ll val)
{
	if (val <= 0 || val > 6 * K) return false;
	if (val > 5 * K) return val % 3 == 0;
	if (val % 3 == 0) return true;
	return val != 1 && val != 5 * K - 1;
}
IN bool c4(R ll val)
{
	if (val <= 0 || val > 3 * K) return false;
	if (val % 3 == 0) return true;
	if (val <= 2 * K && val % 2 == 0) return true;
	if (val <= K) return true;
	return false;
}
IN bool mul() {return (X == 2 * M) || (X == 3 * M) || (X == 4 * M) || (X == 5 * M) || (X == 6 * M);}
IN bool spj()
{
	if (X <= 5 * K && X != 1 && X != 5 * K - 1) return true;
	ll del = X - 2 * K;
	if (del <= 5 * K && del != 5 * K - 1) return true;
	else
	{
		W (del % 3) del += 2;
		if (del > 6 * K) return false;
		return true;
	}
}
int main(void)
{
	scanf("%d", &T);
	scanf("%lld%lld%lld%lld%lld", &A[0], &B[0], &C[0], &D[0], &K);
	scanf("%lld%lld%lld%lld%lld", &A[1], &B[1], &C[1], &D[1], &M);
	scanf("%lld%lld%lld%lld%lld", &A[2], &B[2], &C[2], &D[2], &X);
	W (T--)
	{
		if (spj()) ++ans;
		else if (c1(X - M) || c1(X - 2 * M)) ++ans;
		else if (c2(X - M) || c2(X - 2 * M) || c2(X - 3 * M) || c2(X - 4 * M)) ++ans;
		else if (c3(X - 2 * M)) ++ans;
		else if (c4(X - 2 * M) || c4(X - 3 * M) || c4(X - 4 * M)) ++ans;
		else if (mul()) ++ans;
		K = (A[0] * K % D[0] * K % D[0] + B[0] * K % D[0] + C[0]) % D[0] + 20;
		M = (A[1] * M % D[1] * M % D[1] + B[1] * M % D[1] + C[1]) % D[1] + 20;
		X = (A[2] * X % D[2] * X % D[2] + B[2] * X % D[2] + C[2]) % D[2] + 20;
	}
	printf("%d\n", ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值