2019牛客暑期多校训练营(第一场)A B F J

题目链接:https://ac.nowcoder.com/acm/contest/881#question


Problem A

题意:询问1~n最长区间使得1~n任意子区间询问都有数列的最小值在同一位置。

被队友教会了。

假设P为所求的答案,检查当前P是否合法,由于P具有当前不合法,P+1~n都不可能合法的性质,所以可以使用二分,若当前P合法,那么二分左指针右移,否则右指针左移。

O(n*logn)ST表维护两个数组各自的区间最小下标,这样每次都可以做到O(1)查询

然后判断当前P是否合法的方法是首先判断1~P两个数的最小值下标是否相同。

如果相同,假设这个下标为m,我们可以得知分别处于m两边的l,r的最小值下标一定是m,所以我们只需判断【1,m-1】,【m+1,P】是否合法即可,于是就递归着做就可以,一旦出现一个一个不合法就返回false,二分找下一个可行的P

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

#define ll long long
#define for1(i,a,b) for (int i=a;i<=b;i++)
#define for0(i,a,b) for (int i=a;i<b;i++)
#define df(x) int x;scanf("%d",&x)
#define rd(x) scanf("%d",&x)
#define df2(x,y) int x,y;scanf("%d %d",&x,&y)
#define rd2(x,y) scanf("%d %d",&x,&y)

const int N = 1e5+5;

int sta[N][20],stb[N][20];
int a[N],b[N];

void ST(int st[][20],int a[],int n)
{
    for1(i,1,n) st[i][0] = i;
    for (int j=1;(1<<j)<=n;j++)
        for (int i=1;i+(1<<j)-1<=n;i++)
            if ( a[st[i][j-1]] < a[st[i+(1<<(j-1))][j-1]] ) st[i][j] = st[i][j-1];
            else st[i][j] = st[i+(1<<(j-1))][j-1];
}

bool query(int l,int r)
{
    int k = log(r-l+1.0)/log(2.0);
    int pos1,pos2;
    if (a[sta[l][k]] <= a[sta[r-(1<<k)+1][k]]) pos1 = sta[l][k];
    else pos1 = sta[r-(1<<k)+1][k];
    if (b[stb[l][k]] <= b[stb[r-(1<<k)+1][k]]) pos2 = stb[l][k];
    else pos2 = stb[r-(1<<k)+1][k];
    return pos1==pos2;
}

int qquery(int l,int r)
{
    int k = log(r-l+1.0)/log(2.0);
    int pos1,pos2;
    if (a[sta[l][k]] <= a[sta[r-(1<<k)+1][k]]) return sta[l][k];
    else return sta[r-(1<<k)+1][k];
}

bool check(int l,int r)
{
    if (l>r) return true;
    else if ( query(l,r) ){
        int minpos = qquery(l,r);
        return check(l,minpos-1) && check(minpos+1,r);
    }
    return false;
}

int main()
{
    int n;
    while (~scanf("%d",&n)){
        for1(i,1,n) rd(a[i]);
        for1(i,1,n) rd(b[i]);

        ST(sta,a,n);
        ST(stb,b,n);

        int l = 1,r = n;

        while (l<=r){
            int p = l+r>>1;
            bool flag = check(1,p);
            if (flag) l = p+1;
            else r = p-1;
        }

        printf("%d\n",r);
    }
    return 0;
}


Problem B

数理完蛋。

从这题得出的结论是:

①积分内的常数可以直接移到外面

②积分n项的积不能先各自积分再求积,累加的话是可以的。

\int \frac{1}{x^{2}+a^{2}}dx = \frac{1}{a}*arctan(x)

④累乘变累加:

\frac{1}{(x+a1)(x+a2)(x+a3)...(x+an)} = \sum_{i=1}^{n}(\frac{1}{x+ai}*\prod_{j!=i}^{n}(aj-ai))

之后就是求逆元,累加就完事了

#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;

#define ll long long
#define for1(i,a,b) for (int i=a;i<=b;i++)
#define for0(i,a,b) for (int i=a;i<b;i++)
#define df(x) ll x;scanf("%lld",&x);
#define df2(x,y) ll x,y;scanf("%lld %lld",&x,&y);
#define mod 1000000007

const int N = 1e3+5;

int n;
ll a[N],v[N];

ll GETNY(ll a)
{
    ll b = mod-2;
    ll ans = 1;
    while (b){
        if (b&1) ans = ans*a%mod;
        b >>= 1;
        a = a*a%mod;
    }
    return ans;
}

ll GETA(int idx)///求得当前下标对应的分母一坨值
{
    ll sum = 1;
    for1(i,1,n){
        if (i!=idx) sum = sum*(v[i]-v[idx])%mod;
    }
    sum = sum*a[idx]%mod*2%mod;
    return (sum+mod)%mod; ///上面涉及减法,最后记得加个这个
}

int main()
{
    while (~scanf("%d",&n)){
        for1(i,1,n) scanf("%lld",a+i),v[i] = a[i]*a[i]%mod;
        ll ans = 0;
        for1(i,1,n) ans = (ans+ GETNY(GETA(i)))%mod;

        printf("%lld\n",ans);

    }
    return 0;
}

Problem F

向量叉积求三角形:假设两条边的向量为\vec{A}(x1,y1),\vec{B}(x2,y2),

那么面积 = (\vec{A}×\vec{B})/2 = abs(x1*y2-x2*y1)/2

顺便说一下三维的两条边叉乘可以求体积

V =   \begin{bmatrix} \vec{i} &\vec{j} &\vec{k} \\ x1 & y1 &z1 \\ x2& y2 & z2 \end{bmatrix} /2= (y1*z2-y2*z1, x2*z1-x1*z2, x1*y2-y1*x2) / 2 = ...

网上盗图:

然后期望到底是面积的几分之几直接爆交猜,emm

等于三角形面积的11/18,就当结论记住吧。

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

#define ll long long
#define for1(i,a,b) for (int i=a;i<=b;i++)
#define for0(i,a,b) for (int i=a;i<b;i++)
#define df(x) ll x;scanf("%lld",&x)
#define rd(x) scanf("%lld",&x)
#define df2(x,y) ll x,y;scanf("%lld %lld",&x,&y)
#define rd2(x,y) scanf("%lld %lld",&x,&y)

const int N = 1e5+5;

int main()
{
    ll x1;
    while (~scanf("%lld",&x1)){
        df(y1);
        df2(x2,y2);
        df2(x3,y3);
        ll x,y,xx,yy;
        x = x1-x2;
        y = y1-y2;
        xx = x1-x3;
        yy = y1-y3;

        ll s2 = abs(x*yy-y*xx);

        printf("%lld\n",11*s2);

    }
    return 0;
}


Problem J

除法变乘法,涉及到大数的操作

把1e18的拆成1e9的大位,1e9的小位即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>

using namespace std;

#define ll long long
#define for1(i,a,b) for (int i=a;i<=b;i++)
#define for0(i,a,b) for (int i=a;i<b;i++)
#define df(x) ll x;scanf("%lld",&x)
#define rd(x) scanf("%lld",&x)
#define df2(x,y) ll x,y;scanf("%lld %lld",&x,&y)
#define rd2(x,y) scanf("%lld %lld",&x,&y)

const ll X = 1e9;
const int N = 1e5+5;

int main()
{
    ll x,a,y,b;
    while (~scanf("%lld %lld %lld %lld",&x,&a,&y,&b)){
        ll x1 = x/X,x2 = x%X;
        ll y1 = y/X,y2 = y%X;

        x2 = x2*b;
        x1 = x1*b;
        x1 += x2/X;
        x2 = x2%X;

        y2 = y2*a;
        y1 = y1*a;
        y1 += y2/X;
        y2 = y2%X;

        if (x1==y1 && x2==y2) puts("=");
        else if (x1==y1) printf("%s\n",(x2<y2)?"<":">");
        else printf("%s\n",(x1<y1)?"<":">");

    }
    return 0;
}

之后随缘补辽,有太多的东西不会了o(╥﹏╥)o

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值