御坂美琴
misaka是呱太爺爺的小粉絲,呱太爺爺有一句話說的好:"一尺之棰,日取其半,萬世不竭"。
misaka現在有 n 個呱太玩偶放在一堆,每一次操作,misaka會選擇當前個數 > 1 的一堆呱太玩偶。並將這一堆呱太玩偶分成 和 兩堆,x 是當前這一堆玩偶的個數。現在 misaka 想將玩偶分成 m 堆,其中第 i 堆呱太玩偶的個數是 ai ,你需要告訴 misaka 是否能通過若干次操作將玩偶分成指定的這 m 堆。如果可以輸出 ,否則輸出 。
輸入描述:
第一行兩個數 n, m 。
接下來一行 m 個數 ai 。
輸出描述:
輸出共一個字符串 ,表示 misaka 能否將玩偶分成指定的 m 堆。
輸入
4 1
5
輸出
ham
備註:
1 ≤ n ≤ 10^18, 1 ≤ m ≤ 10^5, 1 ≤ ai ≤ 10^18。
題意:
給定n個物品,每次可以將物品分成數量爲和的兩堆物品,問是否可以分出一個給定長度爲m的物品數量序列.
題解:
每次都能分成兩堆,用隊列模擬分堆,講可能出現的情況標記一下,最後與所給序列對比,如果完全一樣則輸出misaka否則輸出ham
最後還需要特判一下 所給序列的和不超過n (本以爲這個和會爆ll,然而並沒有)
這個題剛開是沒想法,一直以爲是找規律,主要是看到數據很大,但是沒想到他可以用隊列模擬每次一半,可以優化到log級別
另一個坑就是容易爆內存,剛開始的bfs想法是
先把所出現的數都先標記一下,然後與bfs模擬出來的結果相比較,如果相同就cnt++,最後看看cnt是否等於m
然而這種想法,佔用內存太大,,,,
總之一句話,太菜。。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define linf 0x3f3f3f3f3f3f3f3f
ll a[100005];
map<ll,bool>vis;
ll cnt;
ll bfs(ll x)
{
queue<ll>Q;
Q.push(x);
while(!Q.empty())
{
ll u=Q.front();
Q.pop();
if(vis[u])continue;//如果沒有會爆內存
vis[u]=1;
Q.push(u/2);
Q.push(u-u/2);
}
return 0;
}
int main()
{
ll n,m;
ll sum=0;
scanf("%lld%lld",&n,&m);
for(int i=1; i<=m; i++)
{
scanf("%lld",&a[i]);
sum+=a[i];
}
if(sum!=n)
{
printf("ham\n");
return 0;
}
bfs(n);
int flag=1;
for(int i=1; i<=m; i++)
{
if(!vis[a[i]])
{
flag=0;
break;
}
}
if(flag)printf("misaka\n");
else printf("ham\n");
return 0;
}