2019.03.09【NOIP提高组】模拟 B组

JZOJ 4742 单峰

题目

1 ∼ n 1\sim n 1n的排列中有多少个单峰排列


分析

对于 n − 1 n-1 n1 n n n的位置只能在 n − 1 n-1 n1的左右,所以也就是 2 n − 1 2^{n-1} 2n1


代码

#include <cstdio>
#define rr register
using namespace std;
typedef long long ll;
const ll WYC=1000000007;
inline ll modd(ll ans,ll mod){
	rr int f=1;
	if (ans<0) ans=-ans,f=-f;
	if (ans>=(mod<<4)) ans=(ans-(mod<<4))%mod;
	else{
		ans-=(ans>=(mod<<3))*(mod<<3);
		ans-=(ans>=(mod<<2))*(mod<<2);
		ans-=(ans>=(mod<<1))*(mod<<1);
		ans-=(ans>=(mod<<0))*(mod<<0);
	}
	return ans*f;
}
inline ll ksm(ll x,ll y){
	rr ll ans=1;
	for (;y;y>>=1,x=modd(x*x,WYC))
	    if (y&1) ans=modd(ans*x,WYC);
	return ans;
}
signed main(){
	rr ll n; scanf("%lld",&n);
	printf("%lld",ksm(2,modd(n-1,WYC-1)));
	return 0;
}

JZOJ 4743 积木

题目

搭积木必须让上一层底面对于该层完全覆盖(没有凸出来的),问最多搭多高


分析

状压dp,设 d p [ i ] [ n ] [ 0 ∼ 3 ] dp[i][n][0\sim 3] dp[i][n][03]表示当前层用的是第 n n n块积木哪一个面朝上时的最大高度,转移时用未在集合内的积木。


代码

#include <cstdio>
#include <cctype>
#define rr register
#define max(a,b) ((a)>(b)?(a):(b))
#define check(xx1,yy1,xx2,yy2) ((xx1>=xx2&&yy1>=yy2)||(xx1>=yy2&&yy1>=xx2))
using namespace std;
struct rec{int x,y,z;}a[16];
int n,all,k,dp[32768][16][3],ans;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
signed main(){
	all=1<<(n=iut());
	for (rr int i=0;i<n;++i) a[i]=(rec){iut(),iut(),iut()};
	for (rr int i=0;i<all;++i)
	for (rr int j=0;j<n;++j){
		if (i&(1<<j)) continue;
		rr int now=i|(1<<j);
		for (rr int p=0;p<n;++p)
		for (rr int t=0,ch,ku;t<3;++t){
		    if (!t) ch=a[p].x,ku=a[p].y;
		    else if (t&1) ch=a[p].x,ku=a[p].z;
		        else ch=a[p].y,ku=a[p].z;
		    if (check(a[j].x,a[j].y,ch,ku)) dp[now][j][0]=max(dp[now][j][0],dp[i][p][t]+a[j].z);
		    if (check(a[j].x,a[j].z,ch,ku)) dp[now][j][1]=max(dp[now][j][1],dp[i][p][t]+a[j].y);
		    if (check(a[j].y,a[j].z,ch,ku)) dp[now][j][2]=max(dp[now][j][2],dp[i][p][t]+a[j].x);	    
		}
	}
	for (rr int i=0;i<=n;++i)
	for (rr int t=0;t<3;++t) ans=max(ans,dp[all-1][i][t]);
	return !printf("%d",ans);
} 

JZOJ 4745 看电影

题目

N N N个人排成一圈,按顺时针顺序标号为 1 ∼ N 1\sim N 1N,每次随机一个 1 ∼ N 1\sim N 1N的编号,假设随机到的编号是 X X X,如果编号为 X X X人还未踢出,则将这个人踢出,否则看编号为 X X X m o d mod mod N + 1 N+1 N+1(即顺时针顺序下一个编号)的人是否存活,如果还未踢出则将他踢出,否则继续看编号 ( X + 1 ) (X+1) (X+1) m o d mod mod N + 1 N +1 N+1的人,如果已被踢出看顺时针的下一个,以此类推,直到踢出一个人为止。重复上述操作,直到剩下 K K K个人。
已知小S的编号是 I d Id Id,问按照小S的方法来他有多少的概率可以不被踢出,成功得到看电影的机会。


分析

由于这个东西是随机的,通过一些玄学的打表东西可以发现每个人的概率应该是一样的,所以就是 k n \frac{k}{n} nk


代码

#include <cstdio>
#define rr register
using namespace std;
int n,k,t;
inline signed gcd(int a,int b){return b?gcd(b,a%b):a;}
signed main(){
	scanf("%d%d%*d",&n,&k);
	if (!k) printf("0/1");
	    else t=gcd(k,n),printf("%d/%d",k/t,n/t);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值