【PYC#1 欢乐赛】 题解

【题目地址】点击打开链接


【分析们】

【T-1】

树状数组+Trie树


【T-2】

首先显然这是个堆,这个堆以位置为关键字,且形状固定。

我们要做的就是将数字1~N填入堆中,并且令这些数字也满足堆性质。

考虑我们有一个以x为根的堆,有i个数字可以填。

我们用M[i]表示以i为根的堆的结点个数,可以逆序O(N)求得。

用f[i]表示有i个数的方案数。

我们得到一个方程:

        f[i]=C(i-1,m)*f[m]*f[i-1-m]   (m=M[x<<1])

即选择m个分给左儿子,i-1-m个分给右儿子。

具体实现的时候可以用记忆化搜索,注意边界。

复杂度是O(N+log2N)吧


【T-3】

显然最后的形状是一个下凸的单峰函数。

我们直接用三分法求得。

注意将误差阀值设小一点,至少要1e-9才能过。


【代码们】

【T-1】

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <ctime>

using namespace std;

#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define rrep(i,b,a) for(int i=(b);i>=(a);--i)
#define INF (~0U>>1)
#define p_b push_back
#define sf scanf
#define pf printf
#define lowbit(x) ((x)&((~(x))+1))
#define MAXN 100010
#define val(x) ((x)+N)

struct TrieNode{
	#define node TrieNode
	node* ch[2];
	int sz;
	node(){
		ch[0]=ch[1]=NULL;
		sz=0;
	}
}*null=new node(),*root[MAXN],pool[MAXN*400],*New=pool;
int N,M;
int A[MAXN];
vector <node*> Plus;
vector <node*> Sub;

node* Get(){
	New->ch[0]=New->ch[1]=null;
	New->sz=0;
	return New++;
}

void Read(int& x,bool mark=0){
	char tt=getchar();
	for(;tt<'0'||'9'<tt;tt=getchar()) if(tt=='-') mark=1;
	for(x=0;'0'<=tt&&tt<='9';x=(x<<1)+(x<<3)+tt-'0',tt=getchar());
	x=mark?-x:x;
}

void Insert(node* p,int key){
	rrep(i,21,0){
		p->sz++;
		int t=(key>>i)&1;
		if(p->ch[t]==null) p->ch[t]=Get();
		p=p->ch[t];
	}
	p->sz++;
}

void Delete(node* p,int key){
	rrep(i,21,0){
		p->sz--;
		int t=(key>>i)&1;
		p=p->ch[t];
	}
	p->sz--;
}

void Init(){
	Read(N);
	Read(M);
	rep(i,1,N){
		Read(A[i]);
		for(int j=i;j<=N;j+=lowbit(j)){
			if(!root[j]) root[j]=Get();
			Insert(root[j],val(A[i]));
		}
	}
}

int Select(int k){
	int rt=0;
	int n=Plus.size();
	int m=Sub.size();
	rrep(i,21,0){
		int tmp=0,dir=1;
		rep(j,0,n-1) tmp+=Plus[j]->ch[1]->sz;
		rep(j,0,m-1) tmp-=Sub[j]->ch[1]->sz;
		if(k>tmp){
			k-=tmp;
			dir=0;
		}
		else rt+=(1<<i);
		rep(j,0,n-1) Plus[j]=Plus[j]->ch[dir];
		rep(j,0,m-1) Sub[j]=Sub[j]->ch[dir];
	}
	return rt-N;
}

void Solve(){
	int K,a,b,k,p,s;
	while(M--){
		Read(K);
		if(K==1){
			Read(a);
			Read(b);
			Read(k);
			for(int j=b;j;j-=lowbit(j))
			    Plus.p_b(root[j]);
			for(int j=a-1;j;j-=lowbit(j))
			    Sub.p_b(root[j]);
			pf("%d\n",Select(k));
			Plus.clear();
			Sub.clear();
		}
		else{
			Read(p);
			Read(s);
			for(int j=p;j<=N;j+=lowbit(j)){
			    Delete(root[j],val(A[p]));
			    Insert(root[j],val(s));
			}
			A[p]=s;
		}
	}
}

int main(){
	null->ch[0]=null;
	null->ch[1]=null;
	Init();
	Solve();
	return 0;
}

【T-2】

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

#define rep(i,a,b) for(register int i=(a);i<=(b);++i)
#define rrep(i,b,a) for(register int i=(b);i>=(a);--i)
#define INF (~0U>>1)
#define p_b push_back
#define ll long long
#define sf scanf
#define pf printf
#define MAXN 1000010

int N;
ll MODER;
ll f[MAXN];
ll V[MAXN];
int M[MAXN];

void Init(){
	cin>>N>>MODER;
	V[0]=1;
	rep(i,1,N){
		V[i]=V[i-1]*i%MODER;
	}
}

ll Inv(ll a){
	ll b=MODER-2;
	ll rt=1;
	while(b){
		if(b&1) rt=(rt*a)%MODER;
		b>>=1;
		a=(a*a)%MODER;
	}
	return rt;
}

ll C(int i,int j){
	ll fz=V[i];
	ll fm=V[j]*V[i-j]%MODER;
	return fz*Inv(fm)%MODER;
}

ll Dfs(ll x,ll i){
	if(x>N||i==0) return 1;
	if(f[i]) return f[i];
	int m=((x<<1)<=N)?M[x<<1]:0;
	return f[i]=(C(i-1,m)*Dfs(x*2,m))%MODER*Dfs(x*2+1,i-1-m)%MODER;
}

void Solve(){
	rrep(i,N,1){
		if(i*2<=N) M[i]+=M[i*2];
		if(i*2+1<=N) M[i]+=M[i*2+1];
		M[i]++;
	} 
	Dfs(1,N);
	cout<<f[N]<<endl;
}

int main(){
	Init();
	Solve();
	return 0;
}

【T-3】

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define rrep(i,b,a) for(int i=(b);i>=(a);--i)
#define INF (~0U>>2)
#define p_b push_back
#define sf scanf
#define pf printf
#define MAXN 10010
#define eps (1e-10)

int N;
double A[MAXN];
double B[MAXN];
double C[MAXN];

void Init(){
	sf("%d",&N);
	rep(i,1,N){
		sf("%lf%lf%lf",&A[i],&B[i],&C[i]);
	}
}

double F(double x){
	double rt=A[1]*x*x+B[1]*x+C[1];
	rep(i,2,N){
		rt=max(rt,A[i]*x*x+B[i]*x+C[i]);
	}
	return rt;
}

void Solve(){
	double l=0.0,r=1000.0;
	while(fabs(l-r)>eps){
		double m1=l+(r-l)/3;
		double m2=r-(r-l)/3;
		if(F(m1)<F(m2)){
			r=m2;
		}
		else{
			l=m1;
		}
	}
	pf("%.4lf\n",F(l));
}

int main(){
	int T;
	sf("%d",&T);
	while(T--){
	    Init();
	    Solve();
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值