【洛谷2019金秋营模拟赛1】

洛谷2019金秋营模拟赛1

T1 东方CannonBall

好吧这道题我应该只有暴力分 经hy大佬点拨我懂辽 然后我跑去交了代码==

30昏:枚举每个骰子点数,复杂度O(6^(x+y))
60昏: 分别枚举两个骰子的点数,计算出来每种点数和的方案数(除以6^n得到概率) 如果你扔出了\(i\)点,那你胜利的方案是对手扔出\([1,i)\),从小到大枚举你的点数,同时计算对手的前缀和。 6^10≈6e7,直接交可能过不了,注意到x*y比较小可以打表
100昏:
​ 同样计算每种点数的概率
​ 计算n个骰子的概率时,考虑最后一个骰子的点数为1-6的每种情况,可以从n-1个骰 子概率转移过来。
​ 记\(f[i][j]\)表示\(i\)个骰子扔出j的概率
\(f[i][j] = sum{f[i-1][j-k]/6}(1≤k≤6)\)
​ 递推即可,复杂度O(n²)

==并不是很想理解题解里的那个多项式的O(n logn)做法

int main(){
//	freopen("T1.txt","r",stdin);
	rd(n),rd(m),K=Max(n,m);
	for(int i=1;i<=6;++i) f[1][i]=1.0/6.0;
	for(int i=2;i<=K;++i)
		for(int j=i;j<=(i<<2)+(i<<1);++j)
			for(int k=1;k<=6;++k)
				if(j>k&&f[i-1][j-k]) f[i][j]+=f[i-1][j-k]/6.0;
	for(int i=n;i<=(n<<2)+(n<<1);++i)
		for(int j=Min(i-1,(m<<2)+(m<<1));j>=m;--j) ans+=f[n][i]*f[m][j];
	printf("%.2f",ans*100.0);putchar('%');
//	printf("M Used=%.3lf",(double)sizeof(f)/(1<<20));
    return 0; 
}

T2 しろは的军训列队

并没有看懂题解?

绝对值函数是分两段的一次函数
n个绝对值函数之和是n+1段分段一次函数,而这n个斜率变化的点就是aᵢ
按照aᵢ排序,最左边的那一段斜率是所有-bᵢ的和
往右扫,每经过一个点斜率变化+2bᵢ,这样可以得出每一段斜率
然后计算f(a₁),就可以按照斜率依次处理出每个点的函数值
最大值一定在分段处取值,求所有f(aᵢ)的最大值即可

看完 一个带权中位数模板? 一个位置有多个人就一直跳到下一个位置不同的人那里

考场丑代码

==其实我开始打是最暴力的那种暴力 很久没有搞过中位数了

暴力

struct node{int x,y;}a[N];
bool cmp1(node x,node y){return x.x
int main(){
//	freopen("T2.txt","r",stdin);
	rd(n);
	for(int i=1;i<=n;++i){
		rd(a[i].x);if(a[i].x!=a[i-1].x) xda=1;
	}
	sum=nw=0;
	for(int i=1;i<=n;++i) rd(a[i].y),sum+=a[i].y;
	sum>>=1;
//	if(!xda) return puts("0"),0;
	sort(a+1,a+n+1,cmp1);
	int pos;
	for(pos=1;pos<=n;++pos){
		nw+=a[pos].y;
		while(a[pos+1].x==a[pos].x&&pos<=n) nw+=a[++pos].y;
		if(nw>=sum) break;
	}
	ans=0ll;
	for(int i=1;i<=n;++i) ans+=1ll*abs(a[pos].x-a[i].x)*a[i].y;
	printf("%lld",ans);
	return 0; 
}

T3 勇者sky遇上的命中注定的恋人白羽竟然是妹妹2

看完 二昏!

然后就捯饬 每次二分都要分析好久那些边界啥的细节QAQ

然后打完三个样例都过了 美滋滋 觉得可能会超时也没管了==

结果65昏

65昏
struct node{int x,y;}a[N];
int mx,mn;
void query(int x,int y){
	int s=lg[y-x+1];
	mx=Max(Mx[x][s],Mx[y-(1<lim) {++cnt,l=r;continue;}
		if(cnt==k+1) return 0;
	}
	return cnt<=k;
}
void work2(){
	double l=0,r=R,mid;
	while(l+eps=0.5) printf("%.1f\n",r);
	else printf("%d\n",(int)r);
}
int main(){
//	freopen("T3.txt","r",stdin);
	rd(n);
	for(int i=1;i<=n;++i) rd(a[i].x),rd(a[i].y),R=Max(R,a[i].y);
	lg[0]=-1;
	for(int i=1;i<=n;++i) Mn[i][0]=Mx[i][0]=a[i].y,lg[i]=lg[i>>1]+1;
	Mn[n+1][0]=0,Mx[n+1][0]=inf;
	for(int j=1;j<=20;++j)
		for(int i=1;i+(1<

首先撕烤只有一段的情况 极差的取值就是这一段的\((max+min)/2-mn\)

然后多段就可以二分 发现二分过程中会多次询问区间内的极大值和极小值 所以用ST表维护

然后还得优化== 每一段的长度不能像我一样一点一点增加枚举 每一段的长度也可二分!

题解中安利了另一种二分的方式 其实就是二进制拆分

从小到大枚举2ᵏ,如果当前解+2ᵏ仍然合法则加 上。本质是枚举答案的二进制位

struct node{int x,y;}a[N];
int mx,mn;
void query(int x,int y){
	int s=lg[y-x+1];
	mx=Max(Mx[x][s],Mx[y-(1<<s)+1][s]),mn=Min(Mn[x][s],Mn[y-(1<<s)+1][s]);
}
bool check(double lim){
	int l=1,r=1,i;
	for(i=1;l<=n&&i<=k;++i){
		r=l;
		for(int j=20;j>=0;--j)
			if(r+cm[j]<=n){
				query(l,r+cm[j]);
				if(((double)mx+mn)/2.0-mn*1.0<=lim) r+=cm[j];
			}
		l=r+1;
	}
	return l>n;
}
void work2(){
	double l=0,r=R,mid;
	while(l+eps<r){
		mid=((double)l+r)/2.0;
		if(check(mid)) r=mid;
		else l=mid;
	}
	if(r-(int)r>=0.5) printf("%.1f\n",r);
	else printf("%d\n",(int)r);
}

int main(){
	freopen("T3.txt","r",stdin);
	rd(n);
	for(int i=1;i<=n;++i) rd(a[i].x),rd(a[i].y),R=Max(R,a[i].y);
	cm[0]=1,lg[0]=-1;for(int i=1;i<=20;++i) cm[i]=cm[i-1]<<1;
	for(int i=1;i<=n;++i) Mn[i][0]=Mx[i][0]=a[i].y,lg[i]=lg[i>>1]+1;
	Mn[n+1][0]=0,Mx[n+1][0]=inf;
	for(int j=1;j<=20;++j)
		for(int i=1;i+cm[j]-1<=n+1;++i)
		Mx[i][j]=Max(Mx[i][j-1],Mx[i+cm[j-1]][j-1]),
		Mn[i][j]=Min(Mn[i][j-1],Mn[i+cm[j-1]][j-1]);
	rd(m);
	for(int i=1;i<=m;++i) rd(k),work2();
    return 0; 
}
posted @ 2019-10-13 20:36  委屈的咸鱼鱼鱼鱼  阅读(139)  评论(0编辑  收藏  举报