Forever小浮的数学推公式专题题解

B.三足鼎立

题目链接

https://vjudge.net/contest/252255#problem/B

题意

已知s,u,v满足 arctan(1/s) = arctan(1/u)+arctan(1/v) 

求f(s, u, v) = v*u-s*u-s*v的值

思路

直接计算的话因为精度的问题结果可能会不对 于是进行一番推导

①tan(a+b) = ( tan(a) + tan(b)) / (1 – tan(a) * tan(b) )

②tan( atan(x) ) = x

③arctan(1/s) =arctan(1/u)+arctan(1/v)

由①②③得1/s = tan( arctan(1/u)+arctan(1/v)) = (tan(arctan(1/u)) + tan(arctan(1/v)))/(1-tan(arctan(1/u))*tan(arctan(1/v)))= (1/u + 1/v) / (1 - 1/(uv))

化简解一下得到 uv = 1 + us + vs

因此f(s, u, v) = v*u-s*u-s*v=1

所以直接输出1即可

代码

略。。。

C.阿牛的EOF牛肉串

题目链接

https://vjudge.net/contest/252255#problem/C

题意

EOF三个字母组成字符串,不能有两个相连的O,很容易想到递推。

当第n个字母为O时,我们知道我们的第n-1个字母只能为E,F,因此共有2*f(n-2)种可能(前n-2个字母无限制)

当第n个字母为E,F时,我们知道第n-1个字母无限制,此时共有2*f(n-1)种可能。

所以总共的可能数目为2*f(n-1)+2*f(n-2)

即:f(n)=2*f(n-1)+2*f(n-2)

简单递归一下即可

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;

int main(){
    long long fn,fn1,fn2,n,i;
    while(scanf("%lld",&n)!=EOF){
        fn2=3,fn1=8;
        if(n==1){
            printf("3\n");
            continue;
        }
         if(n==2){
            printf("8\n");
            continue;
        }
        for(i=2;i<n;i++){
            fn=2*(fn1+fn2);
            fn2=fn1;
            fn1=fn;
        }
        printf("%lld\n",fn);
    }
    return 0;
} 

D.Tri Tiling

题目链接

https://vjudge.net/contest/252255#problem/D

题意

用1*2的矩形搭建3*n的大矩形,问有多少种搭法

思路

首先可以确定的是奇数肯定都是不行的,直接0,偶数的话:

考虑n的情况,一种为n能够拆分成n1+n2的这种情况,最终结果显然为f(n1)*f(n2)

另外一种为不能用竖线拆分的情况,如果是不能拆分的情况,只能是如下图的这种结构,补全它需要两行。

因此有公式f(n)=3*f(n-2)+2*f(n-4)+…+2*f(0)

求解递推公式只需写出f(n-1)然后作差

得f(n)=4*f(n-2)-f(n-4)

代码

#include <iostream>
#include <math.h>
using namespace std;

int main()
{
	int i,n,a[16];
	a[0]=1;
	a[1]=3;
	a[2]=11;
	for(i=3;i<=15;i++)
		a[i]=4*a[i-1]-a[i-2];
	while(scanf("%d",&n),n!=-1)
	{
		if(n%2==0)
			printf("%d\n",a[n/2]);
		else printf("0\n");
	}
	return 0;
}

E.神、上帝以及老天爷

题目链接

https://vjudge.net/contest/252255#problem/E

题意

n人抽写自己名字的n签,问恰好所有人都抽不到自己的名字签的概率

思路

就是裸的错排,没啥好说的

对于N-1个人,加入一个人,有n-1个人拿错票和n-2个人拿错票两种情况
当有n-1个拿错票时,加入一个人,只要第n个人和前面任意的n-1个人其中一个调换票就可以了,所以有f(n-1)*(n-1)。当有n-2个拿错票时,只能是没拿错的那个人与第n个交换票,而那个人可能是前面n-1个的任意一个,所以又有f(n-2)*(n-1)
所以错排结果为(n-1)*(f(n-1)+f(n-2))

代码

略。

F.FXTZ II 

题目链接

https://vjudge.net/contest/252255#problem/F

题意

有n个能量球,能量分别为 2^0,2^1,2^2,........2^n-1

每次随机选择能量球的概率相同,选择后不能再被选,打中自己和敌人的概率都是50%,

过程中,一旦自己的血量小于对方就算输了,问自己赢的概率。

思路

下面是转自大佬https://blog.csdn.net/a1061747415/article/details/40718009的题解,我的推理方法和它略有不同但是不好说明,结果是相同的。

这题是分析概率题

首先,拿到题目,看到的输出样式是分子除以分母,这样的格式的话,不能只求概率,要用方法数来算

(1)可以确定的是为化简的分母,也就是总方法数,应该是 n 个雪球全排列后,然后再决定每个雪球打在谁身上。

也就是 n! * 2^n  

(2)现在来分析分子,也就是赢的方法数

现在n个雪球排列好了在一排,

可以肯定的是第n个雪球是打在对方身上 ,否则我必输

因为第n个雪球的能量是2^(n-1) 大于剩下的 n-1 个球的能量总和

所以根据第n个球的位置讨论赢的方法数,假设这个球记为x,则其它球记为*

1.第n个雪球在1号位

x***************** 

n-1 个雪球只需要随机排列(n-1)!,并且可以随便打谁2^(n-1) ,所以方法数为:c[n-1][0]*(n-1)!*2^(n-1)

2.第n个雪球在2号位

*x****************

只需要选择1个雪球在左边,n-2个雪球可以随便,所以方法数为:c[n-1][1]*(n-2)!*2^(n-2)

3.第n个雪球在3号位

**x*************** 

只需要选择2个雪球在左边,并且满足要求也就是dp[2],n-3个雪球可以随便,dp[2]*c[n-1][2]*(n-3)!*2^(n-3)

备注:dp[n]记录的是n个雪球时满足要求的方法数

4.第n个雪球在i号位

*******x********** 

只需要选择i-1个雪球在左边,并且满足要求也就是dp[i-1],剩下的n-i个球随便放(n-i)!*2^(n-i)方法,所以方法数dp[i-1]*c[n-1][i-1]*(n-i)!*2^(n-i)

因此,总的赢的方法数dp[n] = sum { dp[i-1]*c[n-1][i-1]*(n-i)!*2^(n-i) } 1<=i<=n

化简:dp[n] = sum { dp[i-1] * (n-1)! * 2^(n-i) / (i-1)!  } 1<=i<=n

即  dp[n] = (n-1)! * ( dp[0]*2^(n-1)/0! + dp[1]*2^(n-2)/1!  + dp[2]*2^(n-3)/2! + ..... + dp[n-2]*2^1/(n-2)! + dp[n-1]*2^0/(n-1)! )

而dp[n-1] = (n-2)! * ( dp[0]*2^(n-2)/0! + dp[1]*2^(n-3)/1!  + dp[2]*2^(n-4)/2! + ..... + dp[n-2]*2^0/(n-2)! )

所以看出: dp[n]=(n-1)*2*dp[n-1]+dp[n-1]

所以  dp[n]=(2*n-1)*dp[n-1] ,dp[0]=1,

所以赢的方法数为:1*3*5*7*...*(2*n-1)

综合(1),(2)得到答案为1*3*5*7*...*(2*n-1) / (n! * 2^n)

 

知道结论后码代码就可以了,需要用到大数。

G.He is Flying 

题目链接

https://vjudge.net/contest/252255#problem/G

题意

一个非负整数组成的数列,记其前缀和为S。对于一段子区间,它对其部分和的贡献为其区间长度。问对于从0到Sn的部分和,其得到的总价值。

思路

数据范围血大无比,而且求所有方法的累计贡献,于是想到生成函数

求解(i−j+1)si−sj−1(i−j+1)si−sj−1

但是想了很久并没有想出来。。。看了大佬的题解 是需要构造4个生成函数,然后将它们两两相乘(卷积),再相减: 

(∑ixsi)(∑x−si−1)−(∑xsi)(∑(i−1)x−si−1)

然后使用FFT进行计算。。。ORZ

H.Toxophily 

题目链接

https://vjudge.net/contest/252255#problem/H

题意

一个人站在(0,0)处射箭,箭的速度为v,问是否能够射到(x,y)处,并求最小角度。

思路

h=vy*t-0.5*g*t*t

vx=v*cos(a)

vy=v*sin(a)

t=x/vx

可得:h=x*tan(a)-(g*x*x)/(2*v*v)/cos(a)/cos(a)

g,x,v已知,设A=x,B=(g*x*x)/(2*v*v)

原式等价于:h=A*tan(a)+(-B/(cos(a)^2))

h函数是上凸函数,三分找到hmax,如果能达到再二分找到最小仰角就可以了

I.FSF’s game 

题目链接

https://vjudge.net/contest/252255#problem/I

题意

给定一个整数n,求∑fun(i,j)(1<=i<=j<=n)。其中fun(i,j)=∑i*j/gcd(i/k,j/k)(k为i和j的公因子),也就是求∑n1i∗j/gcd(i/k,j/k)

思路

根据题意可以得到cal(i,n)=i∗n/gcd(i/k,n/k)=i∗n/gcd(i/k,n/k)(k为i和n的因子)
那么f(n)=f(n−1)+∑caln1(i,n)
拆一下就变成了n/gcd(1/k,n/k)+2n/gcd(2/k,n/k)+...+nn/gcd(n/k,n/k)
很容易得到,对于每一项而言, gcd必然为n的因子,所以在利用筛因子的方法,可以枚举gcd,然后很容易求得当前gcd下的个数为n / gcd,用等差求和公式求gcd加上(n/gcd+1)∗(n/gcd)∗n然后递推一下就有结果了

J.汉诺塔III

题目链接

https://vjudge.net/contest/252255#problem/J

题意

改变了汉诺塔的规则,不能从左边的柱子移动到右边的柱子,需要经过中间的柱子移动,问n片从最左到最右需要多少步。

思路

假设有N个圆盘,则可以分为以下几步

1.最上面的n-1个移动到3号杆子上

2.把第n个从1移动到2柱上

3.把前n-1再从3柱移动到1柱上

4.把第n个从2移动到3

5.再把前n-1个从1移动到3

可以很容易的得到递推式为f(n)=3*f(n-1)+2

其中f (1)=2, 稍微进行一下公式的调整就能得到通项公式为f(n)=3^n-1

K.The Boss on Mars

题目链接

https://vjudge.net/contest/252255#problem/K

题意

求1-n中所有与n互质的数的四次方的和

思路

这个想了一下应该求1到n四次方的和有一个公式 百度了一下果然有QAQ

1^4+2^4+3^4+4^4+……+n^4=n(n+1)(2n+1)(3n^2+3n-1)/30 

然后就可以用容斥原理搞定它

先找到所有的质因子

然后比如说求2的倍数就可以用2*(1^4+2^4+3^4+4^4+……+(n/2)^4)

用容斥计算出与N不互质的和,然后再作差就可以了

附上大佬代码

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std ;
const int maxn = 1010 ;
typedef __int64 ll ;
const __int64 mod = 1e9+7 ;
int p[maxn] ;
int len ;
ll  inv ;
void get_prime(ll n)
{
    len = 0 ;
    for(int i = 2;i*i <= n;i++)
    {
        if(n%i == 0)p[++len] = i;
        while(n%i==0)n/=i ;
    }
    if(n>1)p[++len] = n ;
}
ll Pow(ll a , ll b)
{
    ll c = 1 ;
    while(b)
    {
        if(b&1)c = (c*a)%mod;
        a = (a*a)%mod;
        b >>= 1;
    }
    return c ;
}
ll dfs(int pos , int n)
{
    ll ans = 0 ;
    for(int i = pos;i <= len ;i++)
    {
        ll t = n/p[i] ;
        ll t_1 = ((((6*Pow(t,5) + 15*Pow(t,4) + 10*Pow(t,3) - t))%mod)*inv)%mod;
        ans = (ans + (Pow(p[i] , 4)*(t_1- dfs(i+1 , n/p[i]))))%mod;
    }
    return ans ;
}
int main()
{
    int T ;
    scanf("%d" , &T) ;
    inv = Pow(30 , mod - 2) ;
    while(T--)
    {
        ll n ;
        scanf("%I64d" , &n) ;
        get_prime(n) ;
        ll ans = (((((6*Pow(n,5) + 15*Pow(n,4) + 10*Pow(n,3) - n))%mod)*inv)%mod - dfs(1 , n))%mod ;
        printf("%I64d\n" , (ans+mod)%mod);
    }
    return  0 ;
}

L.Counting Triangles

题目链接

https://vjudge.net/contest/252255#problem/L

题意

数三角形。。。没啥说的

思路

边为n的三角形的三角形数f(n)=原来的边等于n-1的三角形数f(n-1)+第n层增加的三角形2*n-1+正的边大于1的三角形数n*(n-1)/2+倒的三角形数;

即f(n)=f(n-1)+2*n-1+n*(n-1)/2+倒三角形

倒的三角形第四层1个,第五层2个,第6层4个

所以可以按照奇偶分两种情况:

当n为偶数时就为1+3+5+……+(n-3);

当n为奇数时就位2+4+6+……+(n-3);

没考虑倒着的三角形就会GG的。。。

M.循环多少次

题目链接

https://vjudge.net/contest/252255#problem/M

题意

思路

循环的结果为C(n,m)=n!/(m!*(n-m)!)

但是这个数太大了 不太行

用组合数的一个递推公式C(n,m)=C(n,m-1)+C(n-1,m-1)

也可以用杨辉三角来思考,结果是一样的

附上抄的代码

#include
using namespace std;
int arr[2003][2003];
void set(){   
    int i,j;
    for(i=1;i<=2000;i++)
        arr[1][i]=i%1007,arr[i][i]=1;
    for(i=2;i<</FONT>2000;i++)
    {
        for(j=i+1;j<=2000;j++)
        {
            arr[i][j]=(arr[i-1][j-1]+arr[i][j-1])%1007;
        }
    }   
}
int main()
{
    set();
    int t,m,n;
    while(cin>>t)
    {
        while(t-- && cin>>m>>n)
        {   
            cout<<arr[m][n]%1007<<endl;           
        }
    }
    return 0;
}

N.GCD?LCM! 

题目链接

https://vjudge.net/contest/252255#problem/N

题意

计算S(n)mod 258280327.其中[exp],exp是一个逻辑表达式,如果exp为真,[exp]=1,否则[exp]=0;

思路

疯狂公式推导然后求出递推,看了一下和大佬的做法一样,果断帖图

然后根据这个公式打表直接算就可以了。

O.彼岸

题目链接

https://vjudge.net/contest/252255#problem/O

题意

有红黄蓝三张颜色来涂色,连续的三块不能是三种不同的颜色,问涂n块有多少种情况

思路

递推找规律,和前面一道题挺像的;

若前两块的颜色相同,那么下一块可以涂三种颜色;

如果前两块的颜色不同,那么下一块可以涂两种颜色。

羸弱开两个数组a,b分别记录 最后两块颜色相同的情况数 和 最后两块颜色不同的情况数。

很显然的,a1 = 3; b1 = 0; an+1 = an + bn; bn+1 = 2*an + bn;

f(n)=a(n)+b(n)

代码

#include <iostream>
#define maxn 50
int a[maxn],b[maxn];
using namespace std;
int main()
{
	int T,i,n;
	cin >> T;
	a[1] = 3; b[1] = 0;
	for (i=2;i<40;++i)
	{
		a[i] = a[i-1]+b[i-1];
		b[i] = a[i-1]*2+b[i-1];
	}
	while (T--)
	{
		cin >> n;
		cout << a[n]+b[n] << endl;
	}
	return 0;
}

P.Snail Alice

题目链接

https://vjudge.net/contest/252255#problem/P

题意

说了一堆废话其实就是求

思路

这题做了好久

Q.Deck

题目链接

https://vjudge.net/contest/252255#problem/Q

题意

在桌子边上叠纸牌,使纸牌超出桌边的长度最长,并且不能掉下去。

即重心最多在桌子边缘上,问给你N张纸牌,最长能超出桌子边缘多长。

思路

把第一块木板的重心放在第二块木板的边缘,把这两块木板的重心放在第三块木板的边缘,把这三块木板的重心放在第四块木板的右边缘⋯⋯利用杠杆原理算一下n 块木板可以伸出桌面 (1 + 1/2 + 1/3 + … + 1/n) / 2 

最终得到一个递推式:a[i] = a[i-1] + 1/i/2

代码


#include<stdio.h>
#include<string.h>
 
int main()
{
    double a[100010];
    a[1] = 0.5;
    int N;
    for(int i = 2; i <= 100000; i++)
        a[i] = a[i-1] + 1.0/i/2;
    printf("# Cards  Overhang\n");
    while(~scanf("%d",&N))
    {
        printf("%5d%10.3lf\n",N,a[N]);
    }
 
    return 0;
}

R.Delivery 

题目链接

https://vjudge.net/contest/252255#problem/R

题意

你要去邮局发一个包裹,有n个窗口,每个都有人,每一个窗口完成一次服务的时间 ti 的分布符合几何分布:ki*e^(-ki*t)

每个窗口当前服务已经进行了ci时间 你会去第一个完成当前服务的窗口,求你从到达邮局到寄完包裹花费总时间的期望

思路

这个概率还要积分 算到一半不会算 还是请教了寝室大佬才推出答案

研究了好几个小时ORZ

附上抄的代码

#include <iostream>
#include <stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<string>
#include<ctype.h>
using namespace std;
#define MAXN 10000
double k[1010];
int main()
{

    int tt;
    scanf("%d",&tt);
    int n;
    int cas=0;
    while(tt--)
    {
        cas++;
        scanf("%d",&n);
        double ans=0;
        for(int i=0;i<n;i++)
        {
            scanf("%lf",k+i);
            ans+=k[i];
        }
        for(int i=0;i<n;i++)
        {
            scanf("%lf",&k[1000]);
        }
        printf("Case #%d: %.6f\n",cas,(n+1)/ans);
    }


    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值