练习杂谈一

练习杂谈1

除了系统的练习之外,偶尔还是要挑点简单的题来找哈自信(其实主要原因为实因为poj服务器经常扯拐,又遇到想做题的时候只有换一个oj了三)

第一题hdu1098
这道题我看到还是基础题,但是我感觉点都不像基础题。。。题目是说有这么个函数:
f(x) = 5x^13 + 13x^5 + kax . 会给出一个k的值,然后找是否存在一个a的值,是的x取任一整数的时候,都能让f(x) % 65 = 0(也就是65 | f(x)) ,刚开始我完全摸不到火门,我感觉多半要化简, 也就是 f(x) = x ( 5x^12 + 13x^4 + ka ) , 然后就是让5x^12 + 13x^4 + ka可以被65整除,这个咋个弄喃,确实就不晓得了。 然后我就东搞西搞, 把题目给出的测试数据带进切 , 我发现要想除尽65 , 就要让ka % 65 = 47, 然后我就直接把这个当成结论了

我后头也想了一个证明,虽然感觉比较扯,·但还是将就了嘛
就是因为要让x为任一整数的时候使得(5x^12 + 13x^4 + ka) % 65 = 0
那就先把x带成1,然后就变成(18 + ka) % 65 = 0
==> ka % 65 = 47
而且是ka只能对65取模过后只能等于47

所以问题就转化成在已知k的的情况下,求最小的a使得 ka % 65 = 47,感觉好像瞬间都可以把它秒杀了,但是我还是整了半天。。。
要想ka % 65 = 47 , 也就是求要有好多个k加起来,然后对65取模过后的值为47(这是废话),其实就是让很多对65取模后的余数相加等于47,这些余数是不同的

比如k = 11
第一个余数就是11他本身
第二个余数是1,因为6个11再除以65就余1
然后1就可以被65除尽,就不能再往下找余数了

比如k = 27
第一个余数就是27他本身
第二个余数是3*27 % 65 = 16
第三个余数是3*27*5 % 65 = 15
第四个余数是3*27*5*5 % 65 = 10
第五个余数是3*27*5*5*7 % 65 = 5
然后5就可以被65除尽,就不能再往下找余数了

这里写图片描述
这个就是(余数, 这个余数对应需要k的数量)

其实说白了,就是用能搞找到的这些余数来堆出47(应该是n*65 + 47 , 因为就算超出47也可以毕竟最后都是要取65的模,比如177 % 65 = 47)
但是又咋个实现这个过程喃,就是给出一些数要求从他们中任一取数量来堆满一些值,还要让选出来的这些值得重量最小(也就是k的数量最小,因为每一个余数都对应了一个k的数量), 这时候是不是感觉似曾相识, 对~ 就是 完全背包 三 , 哇~我开始的时候还以为做多用点数论小知识就可以做这道题了,没想dp都来了,这应该是多亏了前段时间背包dp的练习

#include<iostream>
#include<cstring>
using namespace std;
#define N 65
#define inf 0x3f3f3f3f
int k;
int v[70], w[70];
int length = 0;
int shuzu[10000];

int main(){
    while(cin >> k ){
        length = 0;
        int a;
        int temp = k % N;
        v[length] = temp;
        w[length++] = 1;
        while(temp && N%temp){
            a = N / temp;
            temp = (a+1)*temp % N;
            v[length] = temp;
            w[length] = w[length-1] * (a+1);
            length ++;          
        }

        //for(int i = 0; i < length; i++) 
        //cout << "(" << v[i] << " " << w[i] << ") "; cout << endl;
        memset(shuzu, 0x3f, sizeof(shuzu));
        shuzu[0] = 0;
        for(int i = 0; i < length; i++){
            for(int j = v[i]; j < 10000; j++){
                if(shuzu[j] > shuzu[j-v[i]] + w[i])
                   shuzu[j] = shuzu[j-v[i]] + w[i];
            }
        }

        int answer = inf;
        for(int i = 47; i < 10000; i+=65) 
        if(answer > shuzu[i]) answer = shuzu[i];
        if(answer == inf) cout << "no" << endl;
        else cout << answer << endl;
    }
    return 0;
}

第二题poj2757
这道题一看输入输出就把我吓到了,居然输入数据长达1000位,也就是10^1000,哇~~~那么场的数据不管傻子double、long long 还是 long double 都是解决不到的了,我能想到的唯一办法就是字符串,通过字符串来解决,但是还有个问题,那就是10^1000这个数量级如果用O(n)来解决,必死无疑,肯定超时,那咋个办喃? 反正我就是找规律嘛。
比如,以b = 5时, 有如下一些数据符合要求
1 , 4
2 , 3
3 , 2
4 , 1
1 , 0 , 4
1 , 1 , 3
1 , 2 , 2
1 , 3 , 1
1 , 4 , 0
2 , 0 , 3
2 , 1 , 2
2 , 2 , 1
…………
唉 , 找规律还是很烦~ 最后可以总结一些公式,就是前面的用首项加末项乘以项数除以2,然后后面n / b 过后的余数一个一个的找,全程都是用字符串的加减乘除,我开始还幻想用c++写,但是除法实现确实不简单,而且运算的效率还是太低,我就用java来实现方便一些

import java.math.BigInteger;
import java.util.Scanner;

public class Main{  
      public static void main(String[] args){         
          Scanner scanner = new Scanner(System.in);
          BigInteger n = new BigInteger(scanner.next());
          BigInteger b = new BigInteger(scanner.next());
          BigInteger one = new BigInteger("1");
          BigInteger temp[] = n.add( one ).divideAndRemainder(b);

          BigInteger answer = temp[0].subtract( one ).multiply(temp[0]).divide(new BigInteger("2")).multiply( b ).multiply(b).multiply(b);    
          BigInteger zhong = temp[0].multiply(b.multiply(b.subtract(one)).divide(new BigInteger("2")).multiply(b.add(one)));
          answer = answer.add(zhong);

          zhong = temp[1].multiply(temp[0]).multiply(b.multiply(b));
          answer = answer.add(zhong);


          //convert to base b
          BigInteger x = temp[0];
          BigInteger zero = new BigInteger("0");
          int base = 0;
          while(!x.equals(zero)) {
             BigInteger conver[] = x.divideAndRemainder(b);
             x = conver[0];
             base = base + conver[1].intValue();
          }

          int bb = b.intValue();
          int yushu = temp[1].intValue();

          for(int i = 0; i < yushu; i++ ){
             int j = bb - 1;
             for(; j >=0 ; j--){
                 if((base+i+j) % bb == 0) break;                 
             }  
             answer = answer.add(new BigInteger(i*bb + j + ""));
          }

          System.out.println(answer);
      }


}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值