这题有点卡常的味道。。。
正解找规律+高精度。
经过手推后发现样例:
10 2↙
1 2 4 8
3 6
5 10
由于m=2,所以每两个一组,共4组。
哇,这就是规律。
第一次将n除以2m-1,而后找到1~n中奇数的个数并添加到ans。
之后每次都将n除以2m,而后找到1~n中奇数的个数并添加到ans。
最后输出即可。
上标(我压了8位™都还跑了2069ms,重点是我用了很多优化啊(没有吸氧) ):
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define mo 100000000
#define rg register int
using namespace std;
ll a[1310],ans[1310],b[1310];
char c,s[10030];
int T,m,k;
void divide(int div)
{
ll x=0;
for (rg i=a[0];i>0;i--)
a[i]=a[i]+x*mo,x=a[i]%div,a[i]/=div;
while (!a[a[0]] && a[0]>0) a[0]--;
}
void inans()
{
b[0]=a[0];
ll x=0;
for (rg i=b[0];i>0;i--)
b[i]=a[i]+x*mo,x=b[i] & 1,b[i]>>=1;
while (!b[b[0]] && b[0]>0) b[0]--;
ans[0]=max(ans[0],b[0]);
x=0;
for (rg i=1;i<=b[0];i++)
ans[i]+=b[i]+x,x=ans[i]/mo,ans[i]%=mo;
if (x) ans[0]=max(ans[0],b[0]+1),ans[b[0]+1]+=x;
}
int main()
{
freopen("upset.in","r",stdin);
freopen("upset.out","w",stdout);
scanf("%d
",&T);
while (T--)
{
scanf("%s %d",s+1,&m);a[0]=0;
memset(ans,0,sizeof(ans));ans[0]=1;
for (rg i=strlen(s+1);i>0;i-=8)
{
a[++a[0]]=0;
for (rg j=max(i-7,1);j<=i;j++)
a[a[0]]=(a[a[0]]<<1)+(a[a[0]]<<3)+(s[j]^48);
}
divide(1<<m-1);
inans();
if (a[1] & 1)
{
ans[k=1]++;
while (ans[k]==mo) ans[k]=0,ans[++k]++;
}
while (a[0])
{
divide(1<<m);
inans();
if (a[1] & 1)
{
ans[k=1]++;
while (ans[k]==mo) ans[k]=0,ans[++k]++;
}
}
printf("%lld",ans[ans[0]]);
for (rg i=ans[0]-1;i>0;i--)
printf("%08lld",ans[i]);
puts("");
}
return 0;
}