HDU2048 神、上帝以及老天爷(错排公式)
HDU2047 阿牛的EOF牛肉串
HDU2045 不容易系列之(3)—— LELE的RPG难题
HDU2563 统计问题
HDU2046 骨牌铺方格
HDU 2050 折线分割平面
HDU 2709 Sumsets
HDU 1098 Ignatius's puzzle
题解:这个题主要考错排公式,不懂可以看这篇博客传送门。
#include
#include
#include
#include
using namespace std;
int main() {
int t;
scanf("%d", &t);
while (t--) {
int n;
long long sum = 1, a[21] = {0, 0, 1};
scanf("%d", &n);
for (int i = n; i > 0; i--)
sum *= i;
for (int i = 3; i <= n; i++)
a[i] = (i - 1) * (a[i - 1] + a[i - 2]);//排错公式
printf("%.2f%%\n", (float) a[n] * 100 / sum);
}
return 0;
}
题解:这个题主要讨论两种情况, 对于第n格取“O”的情况,为了保证两个“O”不相邻,n-1格有两种可能,即“E”、“F”。对于余下的n-2格,由于第n-1格不取“O”,所以第n-2格不受n-1格的限制。其排列数等于f(n-2)。对于第n格不取“O”的情况,即取“E”、“F”。对于余下的n-1格,由于第n格不取“O”,所以,第n-1格不受n格的限制。其排列数等于f(n-1)。
递推式为:a[i]=2*(a[i-1]+a[i-2])
#include
#include
#include
using namespace std;
int main() {
int n;
long long a[100] = {0, 3, 8};
while (scanf("%d", &n) != EOF) {
for (int i = 3; i <= n; i++)
a[i] = 2 * (a[i - 1] + a[i - 2]);
printf("%lld\n", a[n]);
}
return 0;
}
题解:这是一个递推问题。数组 nums [ n ] 保存 n 个格子有多少种涂法。
n 个格子的涂法可以由 n - 1 个格子的涂法再加 1 个格子得到。n - 1 个格子涂好后,再加 1 个格子就只能涂 1 种颜色,所以nums [ n ] = nums [ n - 1 ] * 1。由 n - 1 个格子递推到 n 个格子的时候,会出现一个问题:原来 n - 1 个格子的首尾两个格子不能同色,加 1 个格子后,原来的 n - 1 个格子的首尾两个格子可以同色了。在 n 个格子出现问题的基础上,反推可知:n - 1 个格子首尾同色的时候,n - 2 个格子肯定合法!所以,n - 1 个格子首尾同色,再加 1 个格子就可以涂 2 种颜色,所以nums [ n ] = num [ n - 2 ] * 2
综上所述:nums [ 1 ] = 3 ; nums [ 2 ] = 6 ; nums [ 3 ] = 6 ; nums [ n ] = nums [ n - 1 ] * 1 + nums [ n - 2 ] * 2。
#include
#include
using namespace std;
int main() {
int n;
long long a[51] = {0, 3, 6, 6};
for (int i = 4; i < 51; i++)
a[i] = a[i - 1] + 2 * a[i - 2];
while (scanf("%d", &n) != EOF)
printf("%lld\n", a[n]);
return 0;
}
题解:f(n)走的步数不仅和f(n-1)有关,还和f(n-2)有关,从f(n-1)->f(n)的过程中会有f(n-2)个三个方向的,因为从f(n-2)->f(n-1)中每一次都会产生一步向上的,只有向上走下一步才能有三种走法,否则两种,所以把三次的减去就得到两次的了,然后依次调用下去。方程是:f(n)=f(n-2)*3+(f(n-1)-f(n-2))*2 =>f(n)=f(n-2)+f(n-1)*2。
#include
#include
#include
using namespace std;
int main() {
long long a[21] = {0, 3, 7};
for (int i = 3; i < 21; i++)
a[i] = 2 * a[i - 1] + a[i - 2];
int t, n;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
printf("%lld\n", a[n]);
}
return 0;
}
题解:假设用arr[i]表示2*i的方格一共有组成的方法数,我们知道arr[1]=1;arr[2]=2;现在假设我们已经知道了arr[i-1]和arr[i-2],求arr[i],所谓arr[i],不过是在2*(i-1)的格子后边加上一格2*1的方格罢了,骨牌在这一格上横着放,竖着放,如果前面i-1块已经铺好,则第i块只有一种铺法,就是竖着放,如果要横着放,也只有一种铺法,不过要求前面i-2块已经铺好!因此arr[i]=arr[i-1]+arr[i-2]。
#include
#include
#include
using namespace std;
int main() {
long long a[51] = {0, 1, 2, 3};
int n;
for (int i = 4; i < 51; i++)
a[i] = a[i - 1] + a[i - 2];
while (scanf("%d", &n) != EOF)
printf("%lld\n", a[n]);
return 0;
}
解题:递推递推,先分析下直线分割平面的情况,增加第n条直线的时候,跟之前的直线最多有n-1个交点,此时分出的部分多出了(n-1)+1。折线也是同理,f(1)=2,f(2)=7,先画好前面n-1条折线,当增加第n条,折线时,此时与图形新的交点最多有2*2(n-1)个,所以分出的部分多出了2*2(n-1)+1,所以推出f(n)=f(n-1)+4*(n-1)+1,n>=3。推导可以看看这篇博客传送门。
#include
int main() {
int t, n;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
printf("%d\n", 2 * n * n - n + 1);
}
return 0;
}
题解:当n是奇数的时候,n可以由前面的偶数的所有情况+1得到,所以当n为偶数的时候a[i]=a[i-1];
当n为偶数的时候它的组合含有1的部分可由比它小的奇数得到,偶数部分可由n/2的组合得到。以6为例子,6的组合有(1,1,1,1,1,1),(1,1,1,1,2),(1,1,2,2),(2,2,2),(1,1,4),(2,4),组合里有一的组合(1,1,1,1,1,1),(1,1,1,1,2),(1,1,2,2),(1,1,2,2),都是5的每个组合加一得到的所以这部分是a[i]=a[i-1],不含有一的组合(2,2,2),(2,4),就是3的组合数每个乘以2得到的,所以这部分是a[i]=a[i/2];,综上,偶数部分的代码是转移方程,a[i]=(a[i-1]+a[i/2])%mod;。
#include
#include
#include
#include
#include
#include
题解:我们可以得到 f(1)=18+k*a;题中求最小的a满足条件,把f(x+1),按二项式展开得f(x+1 ) = f (x) + 5*( (13 1 ) x^12 ...... .....+(13 13) x^0 )+ 13*( (5 1 )x^4+...........+ ( 5 5 )x^0 )+k*a;很容易证明,除了5*(13 13) x^0 、13*( 5 5 )x^0 和k*a三项以外,其余各项都能被65整除,那么也只要求出18+k*a能被65整除就可以了.。而f(1)也正好等于18+k*a。
#include
#include
#include
#include
#include
#include