版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37025443/article/details/84568801
一开始有n个糖果,每一次操作,你可以选择一堆x将其分成两堆,x//2,x-x//2
直到一堆的糖果数量=1就不能进行操作了。
然后现在给你m堆糖果a[1..m],问你能不从n个通过任意操作变成当前的局面
解析:
官方题解:
我们维护当前堆的集合和⽬标集合,每次拿出当前个数最多的⼀堆,和⽬标中个数最多的⼀堆⽐较。如果当前的较 少,那么就是不能。如果相等,就把选出的这两堆扔掉,否则就对当前个数最多的那⼀堆进⾏⼀次操作。 如果操作次数⼤于 或者操作完之后当前堆的集合或⽬标集合还有剩余就是不能,否则就是能。
做的时候大佬发现只要a里面的数都可以通过n变换到,并且a[]的和=sum,那么就是可以的
#include <cstdio>
#include <cstring>
#include<algorithm>
#include<set>
using namespace std;
typedef long long ll;
const int MAXN = 1e5+100;
ll a[MAXN];
ll c[200];
int lnum[2];
ll lval[2];
int vis[2];
set<int> mm;
int main()
{
ll n;
int m;
scanf("%lld%d",&n,&m);
int maxx=0;
int cnt=0;
c[cnt++]=-n;
ll yu=n;
mm.insert(yu);
while(n)
{
c[cnt++]=-n/2;
n/=2;
mm.insert(n);
mm.insert(n+1);
}
mm.insert(2);
mm.insert(1);
//sort(c,c+cnt);
ll sum=0;
int flag=1;
for(int i=1;i<=m;i++)
{
scanf("%lld",&a[i]);
sum+=a[i];
if(mm.count(a[i])==0)
{
flag=0;
}
}
if(!flag||sum!=yu)
{
printf("ham\n");
}
else
{
printf("misaka\n");
}
}
本来想在题解里面找证明的,但是发现这个直接暴力就可以做。
扫描二维码关注公众号,回复:
4894266 查看本文章
用dfs遍历这个操作得到的树,如果在遍历这棵树的时候,可以把a[]里面的数对应到每一个树的结点上,那么就是可以的
那么复杂度最多只会遍历树上的m条链,并且一旦你通过一条链遍历到叶子结点,那么肯定是不行的,这条链上没有点、
可以对应a[]中的数
dfs复杂度为O(m*logn)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <iostream>
#include <map>
#define pb push_back
#define mk make_pair
typedef long long ll;
using namespace std;
typedef pair<int,int> PII;
const int MAXN = 1e5+10;
const ll MOD = 998244353;
ll n,m;
map<ll,int> mp;
int f;
void dfs(ll x)
{
if(!f) return ;
if(mp[x])
{
mp[x]--;
return ;
}
if(x==1) {f=0;return;}
ll tmp=x/2;
dfs(tmp);
dfs(x-tmp);
}
int main()
{
cin>>n>>m;
ll v,sum=0;
for(int i=1;i<=m;i++)
cin>>v,mp[v]++,sum+=v;
f=1;
if(sum!=n) f=0;
if(f) dfs(n);
if(f){
for(auto v:mp)
{
if(v.second>0)
{f=0;break;}
}
}
if(!f) cout<<"ham"<<endl;
else cout<<"misaka"<<endl;
}