QBXT金秋测试题解qwq
game
推一遍期望即可。
两个特判留保底分用的qwq
#include<iostream>
#include<cstdio>
using namespace std;
int n;
double p[1001][1001], ans, g[1001][1001];
int main(){
freopen("game.in", "r", stdin);
freopen("game.out", "w", stdout);
scanf("%d", &n);
for(int i=1; i<=n; i++)
for(int j=0; j<i; j++)
scanf("%lf", &p[i][j]);
if(n==1){
printf("%.2f", p[1][0]);
return 0;
}else if(n==2){
printf("%.2f", p[1][0]*p[2][1]*2+p[1][0]*(1-p[2][1])+(1-p[1][0])*p[2][0]);
return 0;
}else {
g[0][0]=1;
for(int i=0; i<n; i++){
for(int j=0; j<=i; j++){
g[i+1][j+1]+=g[i][j]*p[i+1][j];
g[i+1][j]+=g[i][j]*(1-p[i+1][j]);
}
}
for(int i=0; i<=n; i++)
ans+=g[n][i]*i;
printf("%.2f", ans);
}
return 0;
}
cake
meet in middle。分成两半枚举子集双指针判断即可。
(阿克王poorpool的代码!:
#include <algorithm>
#include <iostream>
#include <cstdio>
using namespace std;
int n, X, a[25], b[25], aa, bb, cnta, cntb, vala[1048595], valb[1048595], tmp;
int main(){
freopen("cake.in", "r", stdin);
freopen("cake.out", "w", stdout);
cin>>n>>X;
aa = n / 2;
bb = n - aa;
for(int i=1; i<=aa; i++)
scanf("%d", &a[i]);
for(int i=1; i<=bb; i++)
scanf("%d", &b[i]);
for(int i=0; i<(1<<aa); i++){
tmp = 0;
for(int j=0; j<aa; j++)
if(i&(1<<j)){
tmp += a[j+1];
if(tmp>X) break;
}
if(tmp<=X) vala[++cnta] = tmp;
}
for(int i=0; i<(1<<bb); i++){
tmp = 0;
for(int j=0; j<bb; j++)
if(i&(1<<j)){
tmp += b[j+1];
if(tmp>X) break;
}
if(tmp<=X) valb[++cntb] = tmp;
}
sort(vala+1, vala+1+cnta);
sort(valb+1, valb+1+cntb);
int i=1, j=cntb, ans=X;
for(; i<=cnta; i++){
while(vala[i]+valb[j]>X && j>0) j--;
if(!j) break;
ans = min(ans, X-vala[i]-valb[j]);
}
cout<<ans<<endl;
fclose(stdin);
fclose(stdout);
return 0;
}
grid
骗到50分即可。
road
显然以s为根建树。我们只需考虑选择变化x到LCA还是y到LCA的路径。分别求出取max。
考虑倍增。用前缀和\(sum(i)\)存点\(i\)到根的边权和,\(f(i,j)\)存\(i\)往上跳\(2^j\)次到达的点,\(fsum(i, j)\)存从\(i\)点到\(f(i,j)\)点的边权和,\(road(i,j)\)存从\(i\)点到\(f(i,j)\)点的路径上,选择最优的\(c\)所得到的最⼩的从\(i\)到\(c\)的路径上边权和。
处理好这些每次询问都很简单了。
#include<iostream>
#include<cstdio>
#define maxn 2000001
using namespace std;
inline int qr(){
int x=0, f=1;
char ch=getchar();
for(;!isdigit(ch); ch=getchar()) if(ch=='-') f=-1;
for(; isdigit(ch); ch=getchar()) x=(x<<3)+(x<<1)+ch-48;
return x*f;
}
int n, head[maxn], tot;
int q, s;
struct edge{
int to, nxt, val;
}e[maxn];
int f[maxn][20], dep[maxn];
int sum[maxn];
int road[maxn][20];
int fsum[maxn][20];
void add(int u, int v, int w){
e[++tot].nxt=head[u];
e[tot].to=v;
e[tot].val=w;
head[u]=tot;
}
void LCA_fst(int u, int fa){
dep[u]=dep[fa]+1;
for(int i=0; i<18; i++){
f[u][i+1]=f[f[u][i]][i];
fsum[u][i+1]=fsum[f[u][i]][i]+fsum[u][i];
road[u][i+1]=min(road[u][i], fsum[u][i]+road[f[u][i]][i]);
}
for(int i=head[u]; i; i=e[i].nxt){
int v=e[i].to;
if(v==fa)continue;
f[v][0]=u;
sum[v]=sum[u]+e[i].val;
fsum[v][0]=e[i].val;
road[v][0]=min(0, e[i].val);
LCA_fst(v, u);
}
}
int LCA(int x, int y){
if(dep[x]<dep[y])swap(x, y);
for(int i=18; i>=0; i--)
if(f[x][i]!=0&&dep[f[x][i]]>=dep[y])
x=f[x][i];
if(x==y)return x;
for(int i=18; i>=0; i--)
if(f[x][i]!=0&&f[y][i]!=0&&f[x][i]!=f[y][i])
x=f[x][i], y=f[y][i];
return f[x][0];
}
int solve(int x, int y){
int ans=0, road_sum=0;
for(int i=18; i>=0; i--){
if(f[x][i]!=0&&dep[f[x][i]]>=dep[y]){
ans=min(ans, road_sum+road[x][i]);
road_sum+=fsum[x][i];
x=f[x][i];
}
}
return ans;
}
int main(){
freopen("road.in", "r", stdin);
freopen("road.out", "w", stdout);
n=qr(), q=qr(), s=qr();
int a, b, c;
for(int i=1; i<n; i++){
a=qr(), b=qr(), c=qr();
add(a, b, c);
add(b, a, c);
}
LCA_fst(s, 0);
while(q--){
a=qr(), b=qr();
int lca=LCA(a, b);
int ans=sum[a]+sum[b]-2*sum[lca];
if(a!=lca) ans=min(ans, sum[b]-sum[lca]+solve(a, lca));
if(b!=lca) ans=min(ans, sum[a]-sum[lca]+solve(b, lca));
printf("%d\n", ans);
}
//system("fc road.ans road.out");
return 0;
}
bride
两层枚举。先枚举可能贿赂的人,再枚举每个人支持与否,求概率取min即可。
不知道为什么错了一个点。
90pts:
#include<iostream>
#include<cstdio>
#include<ctime>
using namespace std;
inline int qr(){
int x=0, f=1;
char ch=getchar();
for(;!isdigit(ch); ch=getchar()) if(ch=='-') f=-1;
for(; isdigit(ch); ch=getchar()) x=(x<<3)+(x<<1)+ch-48;
return x*f;
}
int n, k, a;
int w[10], h[10];
double ans, P;
void dfs2(double pro, int cur, int sum, int support){
if(cur==n+1){
if(support>0) P+=pro*a/(a+sum);
else P+=pro;
}else{
dfs2(pro*h[cur]/100, cur+1, sum+w[cur], support+1);
dfs2(pro*(100-h[cur])/100, cur+1, sum, support-1);
}
}
void dfs(int cur, int used){
if(used==k){
P=0.0;
dfs2(1.0, 1, 0, 0);
ans=max(ans, P);
return;
}
for(int i=cur; i<=n; i++){
if(h[i]>=10){
h[i]-=10;
dfs(i, used+1);
h[i]+=10;
}
}
}
int main(){
freopen("bride.in", "r", stdin);
freopen("bride.out", "w", stdout);
n=qr(), k=qr(), a=qr();
for(int i=1; i<=n; i++)
w[i]=qr(), h[i]=qr();
dfs(1, 0);
printf("%.6f", 1.0-ans);
return 0;
}
climb
各种诡异暴力艹即可骗分。(实际上这题是D2最可做的题qwq
不如吃茶去