「SCOI2011」飞镖

一、前言

[和谐美好]选择结构题

二、题解

一眼做法,枚举系数,然后解线性方程。

然后就贼[和谐美好]难打。



先考虑三个飞镖都扔完

第一个 { } \{ \} {} 里的东西是系数序列,第二个 { } \{ \} {} 里的东西是自变量上确界序列(下确界都是 1 1 1


case 1: 只有一种系数,且一定有一个 2 m 2m 2m

{ 2 m , i , i } \{ 2m, i, i \} {2m,i,i} { 1 , k , k } \{ 1, k, k \} {1,k,k}


case 2: 只有两种系数,且一定有一个 2 m 2m 2m

{ 2 m , i , j } \{ 2m, i, j \} {2m,i,j} { 1 , k , k } \{ 1, k, k \} {1,k,k}


case 3: 只有两种系数,且一定没有 2 m 2m 2m

{ i , 2 , 2 } \{ i, 2, 2 \} {i,2,2} { k , k , k } \{ k, k, k \} {k,k,k}
{ i , i , 2 } \{ i, i, 2 \} {i,i,2} { k , k , k } \{ k, k, k \} {k,k,k}


case 4: 有三种系数

{ 1 , 2 , 3 } \{ 1, 2, 3 \} {1,2,3} { k , k , k } \{ k, k, k \} {k,k,k}


case 5: 一种系数都没有

{ m , m , m } \{ m, m, m \} {m,m,m} { 2 , 2 , 2 } \{ 2,2,2 \} {2,2,2} (第一个变量的系数强制为 2 2 2

{ m , m , m } \{ m, m, m \} {m,m,m} { 0 , 0 , 0 } \{ 0,0,0 \} {0,0,0}


对于 C a s e 1 — 3 Case 1—3 Case13,我们相当于解一个类似于如下的线性方程。 a x + b y = c ax + by = c ax+by=c

我们可以写出它的通解

{ x = x 0 + b g c d ( a , b ) k y = y 0 − a g c d ( a , b ) k \begin{cases} x = x_0 + \frac{b}{gcd (a, b)}k \\ y = y_0 - \frac{a}{gcd (a, b)}k \end{cases} {x=x0+gcd(a,b)bky=y0gcd(a,b)ak

ps: x 0 , y 0 x_0,y_0 x0,y0 表示一组满足要求的特殊解。

这时我们相当于要找一组解,满足 x ∈ [ l 1 , r 1 ] , y ∈ [ l 2 , r 2 ] x \in [l_1, r_1], y \in [l_2, r_2] x[l1,r1],y[l2,r2]

由于只是判断存在性,我们只需要枚举 x x x 满足要求的最大和最小值,算出对应的 y y y 的值,判断是否在区间内,然后交换 x , y x,y x,y 和定义域区间,再判断一下,只要有一个满足就说明有解。

对于 C a s e 4 Case4 Case4 我们只需要满足 x ∈ [ 2 , 6 k ] x \in [2, 6k] x[2,6k] 即可。

对于 C a s e 5 Case5 Case5 我们直接特判



为了代码简洁,投掷次数不足三次的就多传了一个参(标记是否允许等于零),如果能理清枚举思路的话还好,如果没有理清那么我的代码可能就失去了可读性……

三、参考代码

#include <cmath> 
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
#define rep(i,j,k) for (int i = (j); i <= (k); i++)
#define per(i,j,k) for (int i = (j); i >= (k); i--)

template <typename T>
void read (T &x) {
	x = 0;
    T 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 ();
    }
    x *= f;
}
template <typename T, typename... Args>
void read (T &x, Args&... args) {
    read (x); read (args...);
}
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return (x > 0 ? x : -x); }

LL exgcd (LL a, LL b, LL &x, LL &y) {
    if (b == 0) {
        x = 1, y = 0;
        return a;
    }
    LL res = exgcd (b, a % b, y, x);
    y -= (a / b) * x;
    return res;
}

const int Maxn = 3;
const int Maxm = 5;

int t;
LL a[Maxn + 5][Maxm + 5];

LL x[Maxm + 5][Maxm + 5], y[Maxm + 5][Maxm + 5], _gcd[Maxm + 5][Maxm + 5];

bool check (LL Limit, LL k1, LL x1, LL X, bool zero1) {
	if (X % k1) return 0;
    X /= k1;
    LL l, r;
    if (zero1) l = 0;
    else l = x1;
    r = x1 * Limit;
    if (l <= X && X <= r) return 1;
    else return 0;
}
bool judge (LL X, LL Y, LL DX, LL DY, LL num, LL l1, LL r1, LL l2, LL r2) {
	X += DX * num, Y -= DY * num;
	return (l1 <= X && X <= r1) && (l2 <= Y && Y <= r2);
}
bool check (LL Limit, LL k1, LL x1, LL k2, LL x2, LL X, bool zero1, bool zero2) {
	LL l1 = x1, r1 = x1 * Limit, l2 = x2, r2 = x2 * Limit;

    if (zero1) l1 = 0;
    if (zero2) l2 = 0;
	
	if (X % _gcd[k1][k2]) return 0;
	LL f = x[k1][k2] * (X / _gcd[k1][k2]), s = y[k1][k2] * (X / _gcd[k1][k2]);
	LL df = k2, ds = k1;
	
	bool fl = judge (f, s, df, ds, ceil ((l1 - f) * 1.0 / df), l1, r1, l2, r2) | judge (f, s, df, ds, floor ((r1 - f) * 1.0 / df), l1, r1, l2, r2);
	swap (f, s);
	swap (df, ds);
	swap (l1, l2);
	swap (r1, r2);
	fl |= judge (f, s, df, ds, ceil ((l1 - f) * 1.0 / df), l1, r1, l2, r2) | judge (f, s, df, ds, floor ((r1 - f) * 1.0 / df), l1, r1, l2, r2);
	return fl;
}
bool check_three (LL Limit, LL x) {
	return 2 <= x && x <= 2 * Limit + 3 * Limit + Limit;
}

signed main () {
    read (t);
    rep (i, 1, 3)
        rep (j, 1, 5)
            read (a[i][j]);
    
    rep (i, 1, 3)
        rep (j, 1, 3)
            _gcd[i][j] = exgcd (i, j, x[i][j], y[i][j]);

	int cnt = 0;
    rep (step, 1, t) {
        LL k = a[1][5], m = a[2][5], x = a[3][5];
        rep (i, 1, 3) a[i][5] = ((a[i][1] * a[i][5] % a[i][4] * a[i][5] % a[i][4] + a[i][2] * a[i][5] % a[i][4] + a[i][3]) % a[i][4]) + 20;
        
        bool fl = 0;

        rep (i, 1, 3) {
            if (check (k, i, 2, x - 2 * m, 1)) fl = 1;
            if (check (k, i, 1, x - 2 * m - m, 1)) fl = 1;
            if (check (k, i, 1, x - 2 * m - 2 * m, 1)) fl = 1;
        }
        rep (i, 1, 3)
            rep (j, 1, 3) {
                if (check (k, i, 1, j, 1, x - 2 * m, 1, 1)) fl = 1;
            }
        
        rep (i, 1, 3) {
        	if (check (k, i, 1, 2, 2, x, 1, 0)) fl = 1;
        	if (check (k, i, 2, 2, 1, x, 1, 0)) fl = 1;

        	if (check (k, i, 1, 2, 1, x - m, 1, 0)) fl = 1;
        	if (check (k, i, 1, 2, 1, x - 2 * m, 1, 1)) fl = 1;
		}
        
		if (check_three (k, x)) fl = 1;

        if (((2 <= x / m && x / m <= 6) || (x / m == 0)) && x % m == 0) fl = 1;
			
		cnt += fl;
    }
    
    cout << cnt;
    return 0;
}

讲道理,真的卡常 (虽然只是我的[和谐美好]做法)

posted @ 2022-03-29 22:04  C2022lihan  阅读(12)  评论(0编辑  收藏  举报