R1前最后一次hu测

T1.xiz

这里写图片描述
这里写图片描述

分析:
题目描述不准确,不过样例很准确

考虑记一个 w 数组, w [ i ] 表示字符 i 与上一个和ta相同的字符在字符串中的距离,如果没有则记为0
这样T的 w [ i ] 可以很容易的表示出来

但有个问题,在 S w 数组是随着匹配位置变化的
这题一般有两种做法,一种是用kmp匹配,一种是哈希

网上dada的题解(果然是dada,看不大懂)
考虑随着匹配位置的移动把S的哈希值给改掉
记一个 n e x t 数组,表示这个字符下一次会在哪里出现
这里就能看出为什么要求与之前的距离,因为这样可以随着移动通过 n e x t 数组把不符合的值改掉
详细说,如果当前这个 n e x t 的值指向匹配范围还要往后,直接将其指向的那个点的 w 值改为0即可
如果这个点正好在匹配的范围内,则要连带S的哈希值一起改


T2.yja

这里写图片描述

分析:
考场上yy出了60分做法

20% ( r 1 = r 2 = . . . = r n )

正多边形

n = 3

我们发现并没有什么特殊的三角形可以适合所有情况
考虑能不能得到一个函数的形式
这里写图片描述
手玩发现上述的公式有上凸性质,三分 x 即可
( 0 < x < m i n ( b , c ) )
注意:任何一个 r 都有可能是图中所谓的 a

n = 4

四个点的最大凸包有两种情况:

  • 四个点都在凸包上,对角线互相垂直

  • 一个点过于接近原点,转化成 n = 3 的情况

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#define LD double

using namespace std;

const LD eps=1e-8;
const LD Pi=acos(-1.0);
const int N=10;
int n,m,nn;
LD r[N],a[N];
LD A,B,C;

LD Max(LD a,LD b) {
    if (a-b>eps) return a;
    else return b;
}

LD f(LD x) {
    return (x+A)*((sqrt(B*B-x*x))+(sqrt(C*C-x*x)));
}

LD SF() {
    LD l=0,r=min(B,C);
    LD m1,m2;
    while (r-l>=eps) {
        m1=l+(r-l)/3.0;
        m2=r-(r-l)/3.0;
        if (f(m2)-f(m1)<eps) r=m2;
        else l=m1;
    }
    return f((m1+m2)/2)/2.0;
}

LD solve_3() {
    LD ans=0;
    A=a[1]; B=a[2]; C=a[3];
    ans=Max(ans,SF());
    A=a[2]; B=a[1]; C=a[3];
    ans=Max(ans,SF());
    A=a[3]; B=a[1]; C=a[2];
    ans=Max(ans,SF());
    return ans;
}

LD solve_4() {
    LD ans=0;
    LD t=((r[1]+r[2])*(r[3]+r[4]))/2.0;
    ans=Max(ans,t);
    t=((r[1]+r[3])*(r[2]+r[4]))/2.0;
    ans=Max(ans,t);
    t=((r[1]+r[4])*(r[2]+r[3]))/2.0;
    ans=Max(ans,t);
    sort(r+1,r+1+4);
    a[1]=r[2]; a[2]=r[3]; a[3]=r[4];
    ans=Max(ans,solve_3());
    return ans;
}

void solve() {
    LD b=(2.0*Pi)/(LD)n;
    LD ans=0;
    ans=(r[1]*r[1]*sin(b))/2.0;
    ans=ans*(LD)n;
    printf("%0.7lf\n",(double)ans);
}

int main()
{
    freopen("yja.in","r",stdin);
    freopen("yja.out","w",stdout);
    scanf("%d",&n);
    bool flag=1;
    for (int i=1;i<=n;i++) {
        scanf("%lf",&r[i]),a[i]=r[i];
        if (i!=1) {
            if (fabs(r[i]-r[i-1])>eps) flag=0;
        }
    }
    if (n<=2) printf("%0\n");
    else if (flag) solve();
    else if (n==3) printf("%0.7lf\n",(double)solve_3());
    else if (n==4) printf("%0.7lf\n",(double)solve_4());
    return 0;
}

100%

枚举在凸包上是哪些点以及顺序,面积为 1 2 ( r 1 r 2 s i n ( θ 1 ) + r 2 r 3 s i n ( θ 2 ) + . . . + r n r 1 s i n ( θ n ) )
条件是 t 1 + t 2 + . . . + t n = 2 π

拉格朗日乘数 λ = r 1 r 2 c o s ( θ 1 ) = r 2 r 3 c o s ( θ 2 ) = . . . = r n r 1 c o s ( θ n ) )
θ 1 , θ 2 , . . . , θ n 关于 λ 单调
于是二分出 λ ,算出 θ 1 , θ 2 , . . . , θ n


T3.zkb

这里写图片描述
这里写图片描述
这里写图片描述

分析:

40%

1e14一位的高精度(思路来源)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll unsigned long long

using namespace std;

const ll mod=1e14;
const int N=20005;
int n,m;
ll a[N],ans[201],o;

int cmp(const ll &a,const ll &b) {
    return a>b;
}

void sort_down(int l,int r) {
    sort(a+l,a+r+1,cmp);
}

void sort_up(int l,int r) {
    sort(a+l,a+r+1);
}

void solve(int l,int r) {
    for (int i=0;i<201;i++) ans[i]=0LL;
    ans[1]=1LL;
    int d=1;
    for (int i=l;i<=r;i++) {
        for (int j=1;j<=d;j++) 
            ans[j]=(ll)ans[j]*a[i];
        for (int j=1;j<=d;j++) {
            ans[j+1]=ans[j+1]+ans[j]/mod;
            ans[j]=ans[j]%mod;
        }
        if (ans[d+1]>0) d++;
        while (ans[d]>mod) {
            ans[d+1]=ans[d+1]+ans[d]/mod;
            ans[d]=ans[d]%mod;
            d++;
        }
    }
    o=ans[d];
    while (o>=10) o=o/(ll)10;
    printf("%lld\n",o);
}

int main()
{
    freopen("zkb.in","r",stdin);
    freopen("zkb.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
    int opt,x,y,z;
    while (m--) {
        scanf("%d%d%d",&opt,&x,&y);
        if (opt==1) {
            scanf("%d",&z);
            if (z==0) sort_down(x,y);
            else sort_up(x,y);
        }
        else {
            solve(x,y);
        }
    }
    return 0;
}

100%

乘法好烦,但是我们可以乘除变加减(取对数),并且最高位可以直接计算
于是问题转化为区间排序并维护区间和

一个显然的想法是对每一个点开一棵值域线段树,再在全局用一个大线段树维护每个值域线段树之间的关系
排序操作相当于将两端未完全覆盖的值域线段树分裂,同时将中间的值域线段树合并,询问时只要全局线段树中维护一下和就可以了
显然只会有 O ( n ) 次分裂与合并

发布了941 篇原创文章 · 获赞 192 · 访问量 32万+

猜你喜欢

转载自blog.csdn.net/wu_tongtong/article/details/79787500