除了系统的练习之外,偶尔还是要挑点简单的题来找哈自信(其实主要原因为实因为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除尽,就不能再往下找余数了
其实说白了,就是用能搞找到的这些余数来堆出47(应该是n*65 + 47 , 因为就算超出47也可以毕竟最后都是要取65的模,比如177 % 65 = 47)
但是又咋个实现这个过程喃,就是给出一些数要求从他们中任一取数量来堆满一些值,还要让选出来的这些值得重量最小(也就是k的数量最小,因为每一个余数都对应了一个k的数量), 这时候是不是感觉似曾相识, 对~ 就是 完全背包 三 , 哇~我开始的时候还以为做多用点数论小知识就可以做这道题了,没想dp都来了,这应该是多亏了前段时间背包dp的练习
#include
#include
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);
}
}