[ exttt{Description}
]
给一个长度为 (n) 的数列 (a) 和一个全零序列 (v) ,以及一个正整数 (k) 。
第 (i) 秒可以选择任意一个位置 (pos) ,使得 (v_{pos}) 加上 (k^i) ,或是什么都不做。
问能否在若干秒后,对于 (forall i) 都有 (v_i=a_i) 。
[ exttt{Solution}
]
- 其实可以把问题转化为:第 (i) 秒可以选择任意一个位置 (pos) ,使得 (a_{pos}) 减去 (k^i) ,或是什么都不做。问能在否在若干秒后,(a) 变成全零序列。
- 有一个显然的性质:对于任意正整数 (x) ,将 (x) 化成 (k) 进制,设 (x) 的 (k) 进制表示下的第 (i) 位为 (b_i) ,则若要将 (x) 变为 (0) ,则需要减去 (b_0) 个 (k^0) ,(b_1) 个 (k^1) ,(b_2) 个 (k^2) ...
- 注意到,对于每个 (k^i) ,至多只能将其使用一次(只能减去一个 (k^i) ).
- 于是就有一个显然的做法了:开个桶
cnt[i]
表示 " 数列 (a) 的 (k) 进制表示下第 (i) 位的和 " ,处理完这个桶后扫一遍,若 (exists i) 满足 (cnt_i > 1) ,则答案为NO
;否则为YES
。
[ exttt{Code}
]
#include<cstdio>
#include<cstring>
#define RI register int
using namespace std;
const int N=31;
int T;
int n; long long k;
long long a[N];
int cnt[61];
void work()
{
memset(cnt,0,sizeof(cnt));
scanf("%d%lld",&n,&k);
for(RI i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(RI i=1;i<=n;i++)
for(RI j=0;a[i];j++,a[i]/=k)
cnt[j]+=a[i]%k;
for(RI i=0;i<=60;i++)
if(cnt[i]>1)
{
puts("NO");
return;
}
puts("YES");
}
int main()
{
scanf("%d",&T);
while(T--) work();
return 0;
}
[ exttt{Thanks} exttt{for} exttt{watching}
]