1682 GG取数
来源:互联网 发布:电脑系统破坏软件 编辑:程序博客网 时间:2024/05/22 10:31
GG取数
- 描述
任给出正整数n和k(1<=n<=1,000,000 , 0<=k<=n),取数规则如下:
例如n=16,k=4
第一次取数 1 取数后的余数为16-1=15
第二次取数 2 取数后的余数为15-2=13
第三次取数 4 取数后的余数为13-4=9
第四次取数 8 取数后的余数为 9-8=1
当第五次取数时,因为余数是1,不够取,此时作如下处理
余数1+k=5,再从1开始取
第五次取数 1 取数后的余数为5-1=4
第六次取数 2 取数后的余数为4-2=2
由于第七次取数4,但余数为2,又得重新加k,2+4=6,再从1开始取
第七次取数 1 取数后的余数为 6-1=5
第八次取数 2 取数后的余数为 5-2=3
第九次取数 4 但不够取
3+4=7
第九次取数 1 取数后的余数为 7-1=6
第十次取数 2 取数后的余数为 6-2=4
第十一次取数 4 取数后的余数为 4-4=0 正好取完
由此可见,当n=16,k=4时,按上面方法11次取完- 输入
输入共有t+1行,第一行是一个整数t(0<=t<=10000),表示共有t组数据。下面t行,每行有两个int类型的正整数,n和k。
- 输出
每组测试数据对应一行输出。如果正好取完,输出按照取数规则取完所需要的取数次数。如果永远不能取完时,输出”Bad Number!”。
- 样例输入
116 4
- 样例输出
11
- 提示
Math is the most powerful tool for coding!
解题说明:这道题需要知道其中的数学规律,难度还是可以的,请教了一个ACM大牛后知道了该怎么去做。
设fun(n)返回经过一轮计算后的余数,如果n=2^k-1,返回0,否则找到小于n的最大的2^a,返回n-2^a
对于给定的n,如果fun(n)=0,结束
否则设m=fun(n),k=1+2+4+……+a,a=fun(k),a+b=2^c
如果a=0,bad number
1. m>k+2b,m=fun(m+k)
2. m=0
3. m>=b,m-=b
4. m<b,m+=a
2、3、4应该是求解m=-bx+ay,用扩展欧几里德
补记:
今日去请教了刘庆辉老师,大致了解了王锐坚学长的思路,具体如下:
1、首先把n和k都看成二进制数,当n的位数超过k时,n总可以通过有限步降至和k位数相同的情况,假设剩下的数为m。设这里的步数为p
2、把k分解为1000..00(二进制)-a 其中被减数比k的位数高一位,a就是该数与k的差
3、m每次加上k可以看成是加上1000..00(二进制)再减去a
4、要是m能被取完则保证m=-ax+100..00(二进制)y 其中x,y存在正整数解
5、使用拓展欧几里德算法求解该方程,看看是否有解
6、如果存在解,最终的步数为x+p
#include <stdio.h>#include <string.h>int pow[21];int cnt;char mark[1000001];int func(int n) { int i; cnt = 0; for (i = 0; i < 21; i++) { if (n < pow[i]) { return n; } cnt++; n -= pow[i]; } return n;}void solve() { int n, k; int i, j, a, b, m, res; scanf("%d%d", &n, &k); m = func(n); if (m == 0) { printf("%d\n", cnt); return; } res = cnt; for (i = n - m + 1; i >= 0; i--) { if (mark[i] == 1) mark[i] = 0; } mark[m] = 1; while (m > 0) { m = func(m+k); res += cnt; if (mark[m] == 1) { printf("Bad Number!\n"); return; } mark[m] = 1; } printf("%d\n", res);}int main() { int i; int t; pow[0] = 1; for (i = 1; i < 21; i++) { pow[i] = 2 * pow[i-1]; } scanf("%d", &t); while (t--) { solve(); } return 0;}
- 1682 GG取数
- gg
- gg
- GG
- gg
- gg
- gg
- gg
- gg
- gg
- gg
- gg
- gg
- gg
- gg
- GG
- gg
- gg
- Willlam Shakespeare——6、Death in the family
- 适配器模式
- QQ邮箱默认竟然不保存到“已发送”
- C#编写浏览器小结(一)
- 反射机制(转载学习)
- 1682 GG取数
- Android源代码编译和运行常见错误解决方案
- 在Virtualbox的linux客户端中共享window的文件夹,出现“mount:未知的文件系统 `vboxsf'”情况
- VC++ inline 优化的试验
- 一步步搭建Ubuntu环境——Ubuntu下SSH设置
- Spring表单标签和modelAttribute
- javascript客户端检测浏览器
- 新学期计划
- Proof of the deliverables - 完成品的证明