题目链接
题目大意:
思路:构造一个这样的序列。
特判一下答案长度在1,2的情况。
我们假设有解,且长度为 k,那么显然我们可以得到一个等式:
1.设 b数组为每次加的值, b1=0
2. ∑i=1k−12k−i−1∗bi+bn+A∗2k−2=B
因为 bi∈[1,m],所以初始的 b全为 1,最多加到 m,那么我们枚举长度 k。
每次先判断合不合法:即 b全是1的和是不是比 B小,显然比 B才有可能合法。
然后每次去把多余的部分从大到小 (幂次高到低)开始减 ,每次尽量减的最多。
如果最后剩下的在 [1,m]之间即合法,把这部分赋值给 b[k]即可。
细节见代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e5+10;
#define fi first
#define se second
#define pb push_back
int t;
LL a,b,m,ans[N],sum[N],f[N],add[N];
LL g[55][55];
LL vis[55],re[55];
int main() {
ios::sync_with_stdio(false);
f[0]=1;
for(int i=1;i<=50;i++)f[i]=f[i-1]*2;
for(int i=2;i<=50;i++){
for(int j=i-1;j>=1;j--){
g[i][j]=f[i-j-1];
}
g[i][i]=f[0];
}
for(cin>>t;t;t--){
cin>>a>>b>>m;
if(a==b){
cout<<"1\n"<<a<<'\n';
}else if(b-a<=m){
cout<<2<<'\n';
cout<<a<<' '<<b<<'\n';
}else{
int sta=0;
for(int i=3;i<=50;i++){
LL res=0;
int st=0;
memset(vis,0,sizeof vis);
memset(re,0,sizeof re);
if(g[i][1]*a>b)break;//不合法
res=b-g[i][1]*a;
LL need=(1ll<<(i-2))-1;
if(need+1>res)continue;//判断是否可能合法,最后一个至少要留1
for(int j=0;j<=i-3;j++)ans[j]=1;
res-=need+1;
int ma=i-3;
while(ma>=0&&res>1){
LL ud=max(min((res)/(1ll<<ma),m-1),0ll);//不停的减
res-=ud*(1ll<<ma);
ans[ma]+=ud;
ma--;
}
res++;//把之前保留的1加上
if(res<1||res>m)st=1;
if(!st){
add[i]=res;
add[i-1]=ans[0];
for(int j=i-2;j>=2;j--){
add[j]=ans[i-j-1];
}
sum[1]=a;
ans[1]=a;
for(int j=2;j<=i;j++){
ans[j]=sum[j-1]+add[j];
sum[j]=ans[j]+sum[j-1];
}
cout<<i<<' ';
for(int j=1;j<=i;j++)cout<<ans[j]<<' ';
cout<<'\n';
sta=1;
break;
}
}
if(!sta)cout<<-1<<'\n';
}
}
return 0;
}