preparing

QZEZTEST2021.7.27分析

T1 qzez 错误检测

题意

思路

代码

T2 qzez 比赛

题意

题面

\(AB\)两队,每队\(n\)人,两队间进行\(n\)场比赛,每个人都要参赛,对手随机且概率均等。每人都有一个实力值,若一场比赛中两队派出队员的能力值分别为\(A_i\)\(B_j\),那么实力值高的一队能获得\((A_i-B_j)^2\)分。求所有情况中\(A\)队分值减\(B\)队分值的平均值(原题为“期望值”)。

输入格式

第一行一个数\(n\)表示两队的人数为\(n\)
第二行\(n\)个数,第\(i\)个数\(A_i\)表示队伍\(A\)的第\(i\)个人的实力值。
第三行\(n\)个数,第\(i\)个数\(B_i\)表示队伍\(B\)的第\(i\)个人的实力值。

输出格式

输出仅包含一个实数表示\(A\)期望赢\(B\)多少分。答案保留到小数点后一位(注意精度)

样例输入

2
3 7
1 5

样例输出

20.0

样例解释

有两种情况:
\(3-1,7-5\),此时\(A\)队赢\(8\)分。 \(3-5,7-1\),此时\(A\)队赢\(32\)分。 综上,平均值为\(20\)分。

思路

原题的“期望值”其实就是平均值,本题和概率论无关。
从样例中,我们不难发现,本题是要求\(\dfrac{ \sum\limits_{i=1}^{n} \sum\limits_{j=1}^{n} \pm(A_i-B_j)^2}{n}\)。展开完全平方公式,得到其实主要要求\(A_i^2+B_j^2-2A_iB_j\)
分析对于每一个\(A_i\),要计算出\(\dfrac{\sum\limits_{j=1}^{n}{A_i^2+B_j^2-2A_iB_j}}{n}\),显然,把除以\(n\)放在最后输出的时候除会方便许多,那么式子就变成了\(\sum\limits_{j=1}^{n}{A_i^2+B_j^2-2A_iB_j}\),稍微变形一下就得到了\(n*A_i^2+\sum\limits_{j=1}^{n}B_j^2-2*A_i*\sum\limits_{j=1}^{n}{B_j}\)。显然,我们可以预处理出\(B\)的前缀和\(sp\)和前缀平方和\(pp\)应该可以这么叫吧,即\(\sum\limits_{j=1}^{n}B_j^2\))。但是,我们还要注意到有\(\pm\)的存在。我们可以先对\(B\)排序(\(A\)无所谓),之后对于每个\(A_i\),二分(\(lower\)_\(bound\)即可)找到位置\(t\),使得\(A_i\ge B_t\)\(A_i\le B_{t+1}\)\(B_1\sim B_t\)\(A\)队赢,\(B_{t+1}\sim B_n\)\(A\)队输,即对于\(A_i\),我们的结果\(ans\)要加上\((t*A_i^2+\sum\limits_{j=1}^{t}{B_j^2}-2*A_i*\sum\limits_{j=1}^{t}{B_j})-((n-t)*A_i^2+\sum\limits_{j=t+1}^{n}{B_j^2}-2*A_i*\sum\limits_{j=t+1}^{n}{B_j})\),加上前缀和和前缀平方和得到最终结果:

\[(t*A_i^2+pp_t-2*A_i*sp_t)-((n-t)*A_i^2+(pp_n-pp_t)-2*A_i*(sp_n-sp_t)) \]

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#define maxn 50005
#define ll long long
using namespace std;
ll n;
ll a[maxn],b[maxn];
ll sp[maxn],pp[maxn];
ll ansp,ansn,ans;
int main(){
    scanf("%d",&n);
    for(ll i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    for(ll i=1;i<=n;i++){
        scanf("%d",&b[i]);
    }
    sort(a+1,a+1+n);
    sort(b+1,b+1+n);
    for(ll i=1;i<=n;i++){
        sp[i]=sp[i-1]+b[i];
        pp[i]=pp[i-1]+b[i]*b[i];
    } 
    for(ll i=1;i<=n;i++){
        ll t=lower_bound(b+1,b+1+n,a[i])-b-1;
        ansp=a[i]*a[i]*t+pp[t]-2*a[i]*sp[t];
        ansn=a[i]*a[i]*(n-t)+(pp[n]-pp[t])-2*a[i]*(sp[n]-sp[t]);
        ans+=(ansp-ansn);
    }
    printf("%.1lf",(double)ans/n);
    return 0;
}

T3 qzez Devoirs de maths

题意

思路

代码

T4 qzez 序列切割

题意

题面

有一长度为\(n\)的序列\(a\),要求分成\(k\)段,使得每段两端数字不互质,求最小的\(k\)值。

输入格式

第一行\(n\)
第二行空格隔开的\(n\)个数字,\(a_i\)表示第\(i\)个数字

输出格式

最少的切割个数\(k\)

样例输入

6
2 3 3 4 3 3

样例输出

2

样例解释

分成2 3 3 4$/$3 3两段,显然不唯一。

思路

显然此题为划分型\(DP\),我们设\(f_i\)为划分\(1\sim i\)可以得到的最小段数,由此可推出方程式\(f_i=\min\limits_{j=1,\gcd(i,j)>1}^{i}{f_j}+1\),就是说,把\(i,j\)划为一段,\(f_i\)等于\(f_j\)(即\(j\)之前的最佳方案)加\(i,j\)这一段(加一)。
暴力显然过不去,我们要考虑优化。发现每次寻找符合条件的所有\(j\)会浪费太多时间,所以我们注意到,只有有至少一个相同质因数的两个数才不互质,所以,对于每一个\(a_i\),我们只需要找到它的全部质因数,找到前面与它有至少一个相同质因数的数当作\(j\)就可以了。但是,这样找还是时间太长,我们不妨设\(g_i\)为有质因数\(i\)的数的最小\(f\)值,即对于所有有质因数\(i\)的数\(x\)\(g_i=min(f_x)\),这样,式子就变成了\(f_i=\min\limits_{j=prime_i}{g_j}+1\)\(prime\)数组存全部除\(1\)以外的质因数)。
下面考虑\(g\)数组的更新,若现在的\(i\)自己成一段,\(g_{prime_i}=\min(g_{prime_i},f_{i-1})\),若\(i\)和其它一段,就不用更新了。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1000005
using namespace std;
int n;
int a[maxn];
int f[maxn],g[maxn];
int t=0,prime[maxn];
void findprime(int x){
    t=0;
    prime[++t]=x;
    for(int i=2;i*i<=x;i++){
        if(x%i==0){
            prime[++t]=i;
            prime[++t]=x/i;
        }
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    memset(f,0x3f,sizeof(f));
    memset(g,0x3f,sizeof(g));
    f[0]=g[0]=0;
    for(int i=1;i<=n;i++){
        findprime(a[i]);
        f[i]=f[i-1];
        for(int j=1;j<=t;j++){
            f[i]=min(f[i],g[prime[j]]);
        }
        f[i]++;
        for(int j=1;j<=t;j++){
            g[prime[j]]=min(g[prime[j]],f[i-1]);
        }
    }
    printf("%d",f[n]);
    return 0;
}
/*
6
2 3 3 4 3 3
*/
posted @ 2021-07-28 13:48  qzhwlzy  阅读(165)  评论(0)    收藏  举报