【洛谷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;
}