zoukankan      html  css  js  c++  java
  • 前段时间的考试试题

    有趣的序列

    洛谷链接
    这一道题是一道卡特兰数的题,但是因为数据量以及要进行模运算的原因,要采用我先前博客中写到的通项式。当然因为不可以直接算阶乘,因此采取分解阶乘的方法转换成乘法。

    Code

    #include<bits/stdc++.h>
    #define maxn 1000002
    #define Int64 long long
    using namespace std;
    int primes[2*maxn];
    int sum[2*maxn];
    bool isp[2*maxn];
    int newp=0;
    void Eular_Sieve(){
    	for(int i=2;i<2*maxn;i++){
    		if(!isp[i]){
    			primes[++newp]=i;
    		}
    		for(int j=1;j<=newp&&primes[j]*i<2*maxn;j++){
    			isp[primes[j]*i]=true;
    			if(!(i%primes[j]))break;
    		}
    	}
    	return;
    }
    Int64 qkpow(int a,int b,int p){
    	//a的b次方mod p 
    	if(b==1)return a;
    	if(b%2){
    		Int64 t=qkpow(a,b/2,p);
    		t=t*t%p;
    		t=t*a%p;
    		return t;
    	}
    	else {
    		Int64 t=qkpow(a,b/2,p);
    		t=t*t%p;
    		return t;
    	}
    }
    int n,p;
    int main(){
    	
    	scanf("%d%d",&n,&p);
    	Eular_Sieve();
    	for(int i=1;i<=newp;i++){
    		Int64 t=primes[i];
    		Int64 cnt1=0,cnt2=0,cnt3=0;
    		while(t<=2*n){
    			cnt1+=(2*n/t);cnt2+=((n+1)/t);cnt3+=(n/t);
    			t*=primes[i];
    		}
    		sum[i]=cnt1-cnt2-cnt3;
    	}
    	Int64 ans=1;
    	for(int i=1;i<=newp;i++){
    		if(sum[i]){
    			(ans*=qkpow(primes[i],sum[i],p))%=p;
    		}
    	}
    	printf("%lld",ans);
    	return 0;
    	
    }
    

    打气球

    这道题我就不给网址了,yzoj上面最后一页找

    题目描述

    Descrition

    周末何老板到磁器口游玩。街边有小贩在组织一种打气球游戏,何老板很感兴趣。

    店家立了一块布,布上画了N*N的方格,有的方格里挂上了气球,有的没有。

    游戏规则如下:

    第1步.观察。如果每一行都至少有一个方格没有气球,并且每一列都至少有一个方格没有气球,游戏结束。否则进行第2步。

    第2步.抛骰子。店家拿出一个特制的骰子,该骰子有N个面,上面依次有1到N这N 个数字。玩家先后抛两次骰子,设第一次抛出的数字为x,设第二次抛出的数字为y (注:抛出的数字是随机的)。

    第3步.打气球。若坐标为(x,y)的格子里有气球,玩家必须将其打爆。子弹1块钱一发。

    如果该格子没有气球,忽略该格子,玩家不用开枪,但玩家也需要支付给店家1块钱。

    第4步.继续。执行第1步。

    何老板是个神枪手,他能做到百发百中。他想你帮他算算,对于当前给出的这局游戏,预计要花多少钱才能结束。

    Input

    第一行,两个整数N和M,N表示方格的尺寸,M表示游戏开始时,有M个格子里是没有气球的。 接下来M行,每行两个整数x,y,表示坐标为x,y的格子里没有气球。

    Output

    一行,一个实数,完成游戏预计花费,保留2个小数位。

    Sample Input

    5 2 
    2 3 
    4 1
    

    Sample Output

    11.77
    

    如果你想看更多的样例输出,可以去WYX大佬的博客

    分析

    这一道题啊,实际上啊,就是一道期望的题,如果你点开了上面的那一个链接,多半也看见了YB说的话了吧,那么接下来要做的事情就是找出递归的关系
    首先,我们都知道每一个格子概率为1/(n*n)
    我们设有r行已经打掉,c列已经打掉,函数为f[r][c]=......
    那么分类讨论
    1.如果说没有抽到有气球的地方,那么就是他自己乘上没有气球的地方的概率
    2.如果说打掉的地方只能消除行,那么就是乘上f[r-1][c]以及这些地方的概率,只能消除列同理
    3.如果可以同时消去的话,那么就可以类比上面的,写出式子来。
    4.当然最后你应该加上1,因为每打一次收费1

    式子和化简如下

    [f[r][c]=\\ frac{f[r-1][c] imes r(n-c)+f[r][c-1] imes c(n-r)+f[r-1][c-1] imes r imes c+f[r][c] imes(n-r)(n-c)+n^2}{n^2(n-r)(n-c)} ]

    好了,既然已经知道了式子,那么就可以比较容易的做出来了,至于边界,那你也可以自己推出来,你可以选择两种方法,dfs or dp
    我的代码里面把dfs的注释掉了

    Code

    #include<bits/stdc++.h>
    #define maxn 2003
    using namespace std;
    double f[maxn][maxn];
    bool row[maxn],col[maxn];//行 列 
    int n,m;
    double dfs(int r,int c){
    	double ans=0;
    	if(!r&&!c)return 0;
    	if(f[r][c]!=-1)return f[r][c];
    	if(r)ans+=dfs(r-1,c)*r*(n-c);
    	if(c)ans+=dfs(r,c-1)*c*(n-r);
    	if(r&&c)ans+=dfs(r-1,c-1)*r*c;
    	return f[r][c]=(double)(ans+n*n)/(n*(c+r)-c*r);
    }
    int main(){
    	
    	scanf("%d%d",&n,&m);
    	int r=n,c=n;
    	for(int i=1;i<=m;i++){
    		int x,y;
    		cin>>x>>y;
    		if(!row[x])r--,row[x]=true;
    		if(!col[y])c--,col[y]=true;
    	}
    	/*for(int i=0;i<=r;i++){
    		for(int j=0;j<=c;j++)f[i][j]=-1;
    	}
    	dfs(r,c);*/
    	for(int i=1;i<=n;i++){
    		f[i][0]=f[i-1][0]+n/(i+0.0);
    		f[0][i]=f[0][i-1]+n/(i+0.0);
    	}
    	for(int i=1;i<=r;i++){
    		for(int j=1;j<=c;j++){
    			double tmp=f[i-1][j]*i*(n-j)+f[i][j-1]*(n-i)*j+f[i-1][j-1]*i*j+n*n;
    			f[i][j]=tmp/(n*(i+j)-i*j);
    		}
    	}
    	printf("%.2lf",f[r][c]);
    	return 0;
    }
    

    还有一道题,不过比较水,居然用暴力枚举就可以做出来了,早知道我当时就直接枚举了,题目与韩信点兵类似

  • 相关阅读:
    快照原理及场景
    CEP实时分析模型
    请求响应模式
    JMS消息服务模型
    EMF与GEF
    基于SOA的编程模型
    实时计算CEP
    数据库常见的场景
    自签证书服务加入证书验证
    post提交主订单数据(gateway)实现httpapi
  • 原文地址:https://www.cnblogs.com/perisino/p/10384749.html
Copyright © 2011-2022 走看看