题解 人脑图灵机

传送门

首先有一个贪心选 b 的思路,考虑细节
将最优决策表示为 \(xa+yb+z[0, \frac{b}{2}](z\in\{0, 1\})\)
于是发现当 \(a\leqslant\frac{b}{2}\) 时选 \(a\) 和选 \(b\) (不穿甲)等价,所以贪心即可
\(a>\frac{b}{2}\) 时,考虑 \(z\) 的取值,发现若 \(z\) 选 0,可以 exgcd 解出最小正整数解
\(z=1\) 时,所需最小炮弹数是 \(\lfloor\frac{m}{b}\rfloor+[m\not\equiv 0\pmod b]+[m\geqslant a\pmod b]\)
于是……

  • 使用 exgcd 解 \(1e18\) 级的同余方程时,在 m*=x/g 的地方是可能爆 long long 的
  • 当一个数在读入时莫名其妙变成负数时,康康是不是快读写成 if (c='-')
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define ll __int128

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline ll read() {
	ll ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

ll n, m, a, b;

namespace force{
	bool dp[210][10010];
	bool solve() {
		memset(dp, 0, sizeof(dp));
		dp[0][0]=1;
		for (int i=0; i<n; ++i) {
			for (int j=0; j<10010; ++j) if (dp[i][j]) {
				if (j+a<10010) dp[i+1][j+a]=1;
				if (j+b<10010) dp[i+1][j+b]=1;
				for (int k=0; k<=b/2; ++k)
					if (j+k<10010) dp[i+1][j+k]=1;
			}
		}
		return dp[n][m];
	}
}

namespace task1{
	ll x, y, g;
	ll exgcd(ll a, ll b, ll& x, ll& y) {
		if (!b) {x=1; y=0; return a;}
		ll g=exgcd(b, a%b, y, x);
		y-=a/b*x;
		return g;
	}
	bool isable(ll a, ll b) {
		// cout<<"isable: "<<a<<' '<<b<<endl;
		g=exgcd(a, b, x, y);
		// cout<<"g: "<<g<<endl;
		if (m%g) return 0;
		// cout<<"x1y1: "<<x<<' '<<y<<endl;
		ll t=b/g;
		x*=m/g; y*=m/g;
		x=(x%t+t)%t;
		y=(m-a*x)/b;
		// assert(a*x+b*y==g);
		// cout<<"xy: "<<x<<' '<<y<<endl;
		return x>=0&&y>=0&&(x+y)<=n;
	}
	bool solve() {
		ll mid=b>>1;
		if (a<=mid && (m/b)+(m%b!=0)+(m%b>mid)<=n) return 1;
		if (isable(a, b)) return 1;
		if (m%b<=mid && (m/b)+(m%b!=0)<=n) return 1;
		if (m%b>=a && (m/b)+(m%b>a)+1<=n) return 1;
		if (m%b>mid && (m/b)+2<=n) return 1;
		return 0; 
	}
}

signed main()
{
	freopen("turing.in", "r", stdin);
	freopen("turing.out", "w", stdout);

	int T=read();
	while (T--) {
		n=read(); m=read(); a=read(); b=read();
		// puts(force::solve()?"Yes":"No");
		puts(task1::solve()?"Yes":"No");
	}

	return 0;
}
posted @ 2022-01-15 19:54  Administrator-09  阅读(2)  评论(0编辑  收藏  举报