A.GCD Sum
分析: 只需要寻找三次即可。
证明: 考虑一个数被 3 3 3整除, 3 , 6 , 9 , 12 , 15 , ⋯ , 3 ∗ k 3,6,9,12,15,\cdots,3*k 3,6,9,12,15,⋯,3∗k,即每一个被3整除的数区间长度都为 3 3 3,所以对于任意一个数,至多需要操作 3 3 3次就可以找到下一个被 3 3 3整除的数。
至于为什么要找被 3 3 3整除的数,因为被 3 3 3整除的数都有一个性质:各位之和也被 3 3 3整除。这样就可以满足题目条件,一个数字与各位数字之和的 gcd \text{gcd} gcd不为 1 1 1而为3。
利用数学归纳法证明这一性质:
设有整数 a b ab ab被 3 3 3整除,
则有 a b = a ∗ 10 + b = 9 ∗ a + a + b ab=a*10+b=9*a+a+b ab=a∗10+b=9∗a+a+b
要被 3 3 3整除必须有 ( a + b ) m o d 3 = 0 (a+b)\mod3=0 (a+b)mod3=0
设有整数 a b c abc abc被 3 3 3整除,
则有 a b c = a ∗ 100 + b ∗ 10 + c = 99 ∗ a + 9 ∗ b + a + b + c abc=a*100+b*10+c=99*a+9*b+a+b+c abc=a∗100+b∗10+c=99∗a+9∗b+a+b+c
要被 3 3 3整除必须有 ( a + b + c ) m o d 3 = 0 (a+b+c)\mod3=0 (a+b+c)mod3=0
设整数 a ⋯ k a\cdots k a⋯k被3整除,
则有 a ⋯ k = 99 ⋯ 9 ∗ a + ⋯ + a + ⋯ + k a\cdots k=99\cdots9*a+\cdots+a+\cdots+k a⋯k=99⋯9∗a+⋯+a+⋯+k,
要被 3 3 3整除必须有 ( a + ⋯ + k ) m o d 3 = 0 (a+\cdots+k)\mod3=0 (a+⋯+k)mod3=0
设整数 a ⋯ k ( k + 1 ) a\cdots k(k+1) a⋯k(k+1)被3整除,
则有 a ⋯ k ( k + 1 ) = 99 ⋯ 9 ∗ a + ⋯ + a + 9 ∗ k + ⋯ + k + ( k + 1 ) a\cdots k(k+1)=99\cdots9*a+\cdots+a+9*k+\cdots+k+(k+1) a⋯k(k+1)=99⋯9∗a+⋯+a+9∗k+⋯+k+(k+1),
要被 3 3 3整除必须有 ( a + ⋯ + k + ( k + 1 ) ) m o d 3 = 0 (a+\cdots+k+(k+1))\mod3=0 (a+⋯+k+(k+1))mod3=0
代码:
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
LL gcd(LL a,LL b){
return b==0?a:gcd(b,a%b);
}
int t;
LL n;
int main(){
cin>>t;
while(t--){
cin>>n;
LL wei=0,tmp=n;
while(tmp){
wei+=tmp%10;
tmp/=10;
}
while(gcd(n,wei)==1){
n++;
tmp=n;
wei=0;
while(tmp){
wei+=tmp%10;
tmp/=10;
}
}
cout<<n<<endl;
}
}
B. Box Fitting
分析: 先初始化宽度为 k k k,高度为 1 1 1,将方格从大到小排序,每次取最大的方格,往里面放,如果放不下去,那么就新增高度,因为显然长度大的方块比长度小的方块最优。
这里排序可以利用 2 2 2的幂次方这一性质,从大到小枚举,题目数据范围为 1 e 9 1e9 1e9,故而方块的幂只能 ≤ 19 \le 19 ≤19。
#include<bits/stdc++.h>
using namespace std;
int t,n,w,x;
int main(){
cin>>t;
while(t--){
vector<int> a(20);
cin>>n>>w;
int cnt=1,res=w;
for(int i=0;i<n;i++){
cin>>x;
a[log2(x)]++;
}
for(int i=0;i<n;i++){
int flag=-1;
for(int j=19;j>=0;j--){
if(a[j]&&(1<<j)<=res){
flag=j;
break;
}
}
if(flag==-1){
res=w;
cnt++;
for(int j=19;j>=0;j--){
if(a[j]&&(1<<j)<=res){
flag=j;
break;
}
}
}
a[flag]--;
res-=(1<<flag);
}
cout<<cnt<<endl;
}
}