进制转化,这里讲两种思路。
先说两个性质 :一,一个数(默认十进制)对k取模得到的是这个数在k进制下的最后一位。
二,一个数(默认十进制)除以k得到的是这个数在K进制下去掉最后一位的十进制数。
第一种思路就是利用这两个性质,分别统计k进制下从右到左从0位到最后一位上的数字,这个数字是几其实即代表要用几个k^i去补(i是当前位置),然后显然由题意这个数是不能大于1的,我们统计一遍,然后判断一下就行。
AC代码:
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
ll n,k,num[1000];
void get_num(ll x){
int cnt=0;
while(x){
num[++cnt]+=x%k;
x/=k;
}
return ;
}
int main(){
int t;
cin>>t;
while(t--){
memset(num,0,sizeof(num));
cin>>n>>k;
for(int i=1;i<=n;i++){
ll aa;
cin>>aa;
get_num(aa);
}
int flag=1;
for(int i=1;i<=100;i++){
if(num[i]>1)flag=0;
}
if(flag)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
再说说我自己的,直接凑数,从大的开始凑,然后用vis[]记录是否使用过这个数,最后只要不能凑成就一定是NO
AC代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
ll a[50],num[50];
ll vis[50];
ll po(ll x,ll y) {
ll sum=1;
for(int i=1; i<=x; i++) {
sum=sum*y;
}
return sum;
}
int main() {
int t;
cin>>t;
while(t--) {
memset(vis,0,sizeof(vis));
memset(a,0,sizeof(a));
memset(num,0,sizeof(num));
ll n,k,jj=1;
cin>>n>>k;
num[0]=1;
//for(int i=1;i<=10;i++){sum=sum*9;cout<<i<<" "<<sum<<" "<<po(i,9)<<endl;}
for(int i=1; i<=100; i++) {
num[i]=po(i,k);
jj=i;
if(num[i]>1e16)break;
}
for(int i=1; i<=n; i++)cin>>a[i];
int flag=1;
for(int i=1; i<=n; i++) {
if(!a[i])continue;
ll temp=a[i];
for(int j=jj; j>=0; j--) {
if(temp>=num[j]&&!vis[j]) {
temp-=num[j];
vis[j]=1;
}
}
if(temp!=0) {
//cout<<i<<" "<<a[i]<<" "<<endl;
flag=0;
}
}
if(flag)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}