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即可
略。。。
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
#include
#include
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
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
#include
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;
}
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))
略。
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)
知道结论后码代码就可以了,需要用到大数。
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
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,如果能达到再二分找到最小仰角就可以了
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然后递推一下就有结果了
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
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
#include
#include
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 ;
}
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的。。。
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<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<
https://vjudge.net/contest/252255#problem/N
计算S(n)mod 258280327.其中[exp],exp是一个逻辑表达式,如果exp为真,[exp]=1,否则[exp]=0;
疯狂公式推导然后求出递推,看了一下和大佬的做法一样,果断帖图
然后根据这个公式打表直接算就可以了。
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
#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;
}
https://vjudge.net/contest/252255#problem/P
说了一堆废话其实就是求
这题做了好久
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
#include
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;
}
https://vjudge.net/contest/252255#problem/R
你要去邮局发一个包裹,有n个窗口,每个都有人,每一个窗口完成一次服务的时间 ti 的分布符合几何分布:ki*e^(-ki*t)
每个窗口当前服务已经进行了ci时间 你会去第一个完成当前服务的窗口,求你从到达邮局到寄完包裹花费总时间的期望
这个概率还要积分 算到一半不会算 还是请教了寝室大佬才推出答案
研究了好几个小时ORZ
附上抄的代码
#include
#include
#include
#include
#include
#include
#include
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