洛谷 P7774 KUTEVI 题解

本文解析了一个关于通过加减运算构造特定角度的数学问题,介绍了使用深度优先搜索的方法,展示了如何避免重复并证明了不枚举减法的必要性。通过代码实现,博主分享了解决此类问题的算法和证明过程。

写这篇题解花了我很多不少时间,希望能过 awa


题意:

mmm 个数,这 mmm 个数能否由另外 nnn 个数通过加减运算获得。

对于每一次加减的操作,结果不能小于 000(角度不能小于 000);
对于大于等于 360360360 的结果,对 360360360 取模。(大于 360∘360^{\circ}360 的角会转一圈后继续转)

能则输出 YES ,不能则输出 NO 。

思路:

dp\texttt{dp}dp(背包)、搜索都可以。dp 太难想 这里我只讲搜索。

对于每一个状态,只有加和减两种状态。所以只需要对每一个状态枚举每一个数的加或减。

记录已经过状态,枚举中遇到了要获得的数,就表明可以实现。枚举结束后还没有遇到,则不能实现。

实现:

对于状态 xxx

拓展 (x±a[i]) mod 360(x\pm a[i]) \bmod 360(x±a[i])mod360x±a[i]≥0x\pm a[i]\ge0x±a[i]0 且未被拓展过。

上代码!

#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[11],b;
bool vis[361];

bool bfs(int end)
{
	memset(vis,0,sizeof(vis));
	queue<int> q;
	q.push(0);
	vis[0]=true;
	while(!q.empty())
	{
		int t=q.front();q.pop();
		if(t==end)
		{
			return true;
		}
		for(int i=1;i<=n;i++)
		{
			int cg=(t+a[i])%360;
			if(cg>=0&&(!vis[cg]))
			{
				vis[cg]=true;
				q.push(cg);
			}  //可以不枚举减法,文后给出证明过程
			/*cg=(t-a[i])%360;  
			if(cg>=0&&(!vis[cg]))
			{
				vis[cg]=true;
				q.push(cg);
			}*/
		}
	}
	return false;
}

int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=m;i++)
	{
		cin>>b;
		if(bfs(b)) puts("YES");
		else puts("NO");
	}
	return 0;
}

完结。


对于可以不枚举 x−ax-axa 的证明:

对于任意正整数 xxxaaakkkppp,证明:

(x+ak) mod 360=x−ap(x+ak) \bmod 360 = x-ap(x+ak)mod360=xap

xxx 指某一状态。意思就是,只用加 kkkaaa 就可以枚举到 x−apx-apxap

原式可转化为: 360t+x−ap=x+ak360t+x-ap=x+ak360t+xap=x+akttt 为任意正整数。

化简,得:360t=a(p+k)360t=a(p+k)360t=a(p+k)

所以,只需证明 a(p+k)a(p+k)a(p+k) 恒为 360360360 倍数。

aaa360360360 倍数,得证;

aaa 不为 360360360 倍数,

则若使 (p+k)(p+k)(p+k)360360360 倍数,k=360−pk=360-pk=360p 即可。

又有 x−ap≥0x-ap\ge0xap0,则 p≤xa<360p\le \frac{x}{a}<360pax<360

kkk 在满足 k=360−pk=360-pk=360p 的条件下满足 k>0k>0k>0,所以无论 ppp 取多少都能满足 (p+k)(p+k)(p+k)360360360 倍数。得证。

综上,(x+ak) mod 360=x−ap(x+ak) \bmod 360 = x-ap(x+ak)mod360=xap


第一次自己写 OI 证明题,有不对或不完善的地方请指出,谢谢qaq;

被打回x4 – 求过!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值