为了解决高中留下的一些整数分解问题而进行必要的学习
为了解决高中留下的一些整数分解问题而进行必要的学习
???来源于一道题having a lunch(想了好久的做不出)
这是三元姐姐区(习题区名称)的一道题,而且还给出了解释:
作者毫不犹豫地写成了这样,发现测试用例也只有前面两例通过,后面的用例由于复杂度太高了根本解不出来:
#include
long long kinds(int N1) {
long long cnt = 0;
for (int i = 0; i <= 1; i++) {
for (int j = 0; j <= 2; j++) {
for (int k = 0; k <= 3; k++) {
for (int l = 0; l <= N1 + 1; l++) {
for (int m = 0; m <= N1 / 2 + 1; m++) {
for (int n = 0; n <= N1 / 3 + 1; n++) {
if ( i + j + k + l + 2 * m + 3 * n == N1) {
cnt++;
// printf("(%d,%d,%d,%d,%d,%d)\n", i, j, k, l, m, n);
}
}
}
}
}
}
}
// for(long long n=0;n<=N1/3;n++){
// for(long long m=0;m<=N1/2;m++){
// for(long long l=0;l<=N1+6;l++){
// if(l + 2 * m + 3 * n == N1){
// if(l==0||l==N1+6){
// cnt+=1;
// }else if(l==1||l==N1+5){
// cnt+=4;
// }else if(l==2||l==N1+4){
// cnt+=9;
// }else if(l==3||l==N1+3){
// cnt+=15;
// }else if(l==4||l==N1+2){
// cnt+=20;
// }else if(l==5||l==N1+1){
// cnt+=23;
// }else if(l>=6||l<=N1){
// cnt+=24;
// }
// }
// }
// }
// }
return cnt;
}
int main() {
int N1 = 0, N2 = 0;
scanf("%d%d", &N1, &N2);
printf("%lld %lld\n", kinds(N1), kinds(N2));
// int N = 1000;
// printf("%lld", kinds(N));
return 0;
}
后来先办法写成三个,结果还是无济于事
#include
long long kinds(int N1) {
long long cnt = 0;
// for (int i = 0; i <= 1; i++) {
// for (int j = 0; j <= 2; j++) {
// for (int k = 0; k <= 3; k++) {
// for (int l = 0; l <= N1 + 1; l++) {
// for (int m = 0; m <= N1 / 2 + 1; m++) {
// for (int n = 0; n <= N1 / 3 + 1; n++) {
// if ( i + j + k + l + 2 * m + 3 * n == N1) {
// cnt++;
//// printf("(%d,%d,%d,%d,%d,%d)\n", i, j, k, l, m, n);
// }
// }
// }
// }
// }
// }
// }
for(long long n=0;n<=N1/3;n++){
for(long long m=0;m<=N1/2;m++){
for(long long l=0;l<=N1+6;l++){
if(l + 2 * m + 3 * n == N1){
if(l==0||l==N1+6){
cnt+=1;
}else if(l==1||l==N1+5){
cnt+=4;
}else if(l==2||l==N1+4){
cnt+=9;
}else if(l==3||l==N1+3){
cnt+=15;
}else if(l==4||l==N1+2){
cnt+=20;
}else if(l==5||l==N1+1){
cnt+=23;
}else if(l>=6||l<=N1){
cnt+=24;
}
}
}
}
}
return cnt;
}
int main() {
int N1 = 0, N2 = 0;
scanf("%d%d", &N1, &N2);
printf("%lld %lld\n", kinds(N1), kinds(N2));
// int N = 1000;
// printf("%lld", kinds(N));
return 0;
}
原因如下:(测试用例)
| 输入 | 输出 |
|---|---|
| 4 96 | 34 18434 |
| 5 6 | 52 74 |
| 1009876 7 | 2039699070754 100 |
| 1000000000 776543 | 2000000000000000002 1206038061700 |
| 900500400 999500400 | 1621801940800320002 1998002099200320002 |
后面三个数据太大,用三个for显然不正确,复杂度太高;
后面学指答疑群(一个知识交流群)上面的大佬给出解释,再根据自己的理解写一下
大佬说:第一行是根据生成函数写出来的,第一步化简是麦克劳林 ,第二步是公因式 ,第三步是组合数, 最后一步就是得出答案了
??自己理解
问题转化为:
求下式中x^n的系数,
自己先自行初步化解:
然后发现一个问题就是,由麦克劳林公式可得
则有返回上面的重新计算
下面的多项式相乘建议画一下就可以明白,
又需要满足n>=4,
则有x^n的系数K刚好为
最终代码,虽然写的很简洁,但是真的不能从下面这段代码学到很多的东西;
#include
int main() {
long long N1 = 0, N2 = 0;
scanf("%lld%lld", &N1, &N2);
printf("%lld %lld\n", 2*(N1*N1+1), 2*(N2*N2+1));
return 0;
}
打算接下来学一下生成函数再写一篇文章吧。