abc189

AtCoder Beginner Contest 189

A

B

C

n n n 个竖着的条,高度为 a i a_i ai 宽度为 1 1 1 ,在内部选择一个矩形,求其最大面积

由于面积要尽量大,最后选择的矩形肯定会在某处卡到上界,枚举在哪里卡到上界

单调栈预处理每个位置向左向右分别能扩展到的最远位置,然后计算答案

#include <bits/stdc++.h>
using namespace std;
typedef vector <int> vi;
#define pb push_back
const int N = 1500005;
int l[N],r[N],a[N],n;
int main()
{
    cin>>n;for (int i=1;i<=n;++i) scanf("%d",&a[i]);
    vi vc;
    a[0]=a[n+1]=0;
    vc.clear();vc.pb(0);
    for (int i=1;i<=n;++i)
    {
        while (a[i]<=a[vc.back()]) vc.pop_back();
        l[i]=vc.back()+1;
        vc.push_back(i);
    }
    vc.clear();vc.pb(n+1);
    for (int i=n;i;--i)
    {
        while (a[i]<=a[vc.back()]) vc.pop_back();
        r[i]=vc.back()-1;
        vc.push_back(i);
    }
    int ans=0;
    for (int i=1;i<=n;++i) ans=max(ans,a[i]*(r[i]-l[i]+1));
    cout<<ans<<endl;
    return 0;
}

D

给出 N N N 个运算符(逻辑与或者逻辑或),问有多少个数列 X 0 , X 1 , . . . X n X_0,X_1,...X_n X0,X1,...Xn 满足 ( ( ( X 0 S 1 X 1 ) S 2 X 2 ) . . . ) S n X n (((X_0 S_1 X_1)S_2 X_2)...)S_n X_n (((X0S1X1)S2X2)...)SnXn 的取值为真

d p [ i ] [ 0 / 1 ] dp[i][0/1] dp[i][0/1] 表示进行第 i i i 次运算后结果为 0 / 1 0/1 0/1 , X 0 , X 1 , . . . , X i X_0,X_1,...,X_i X0,X1,...,Xi 的方案数

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1500005;
ll dp[N][2];
string op[N];
int n;
int main()
{
    cin>>n;for (int i=1;i<=n;++i) cin>>op[i];
    dp[0][0]=dp[0][1]=1;
    for (int i=0;i<n;++i)
    for (int j=0;j<2;++j)
    for (int k=0;k<2;++k)
    {
        int nw=0;
        if (op[i+1][0]=='A') nw=j&k;else nw=j|k;
        dp[i+1][nw]+=dp[i][j];
    }
    cout<<dp[n][1]<<endl;
    return 0;
}

E

给出n个点,m次操作,q次询问,问第 a 次操作后第 b 个点的坐标

四个操作都可以写成矩阵乘法的形式,记录矩阵的前缀积即可

操作一

[ x y 1 ] [ 0 − 1 0 1 0 0 0 0 1 ] = [ y − x 1 ] \begin{bmatrix} x & y & 1 \end{bmatrix} \begin{bmatrix} 0 & -1 & 0 \\ 1 & 0 & 0 \\ 0 & 0 & 1 \end{bmatrix} = \begin{bmatrix} y & -x & 1 \end{bmatrix} [xy1]010100001=[yx1]

操作二

[ x y 1 ] [ 0 1 0 − 1 0 0 0 0 1 ] = [ − y x 1 ] \begin{bmatrix} x & y & 1 \end{bmatrix} \begin{bmatrix} 0 & 1 & 0 \\ -1 & 0 & 0 \\ 0 & 0 & 1 \end{bmatrix} = \begin{bmatrix} -y & x & 1 \end{bmatrix} [xy1]010100001=[yx1]

操作三

[ x y 1 ] [ − 1 0 0 0 1 0 2 t 0 1 ] = [ 2 t − x y 1 ] \begin{bmatrix} x & y & 1 \end{bmatrix} \begin{bmatrix} -1 & 0 & 0 \\ 0 & 1 & 0 \\ 2t & 0 & 1 \end{bmatrix} = \begin{bmatrix} 2t-x & y & 1 \end{bmatrix} [xy1]102t010001=[2txy1]

操作四

[ x y 1 ] [ 1 0 0 0 − 1 0 0 2 t 1 ] = [ x 2 t − y 1 ] \begin{bmatrix} x & y & 1 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 \\ 0 & -1 & 0 \\ 0 & 2t & 1 \end{bmatrix} = \begin{bmatrix} x & 2t-y & 1 \end{bmatrix} [xy1]100012t001=[x2ty1]

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
const int N = 1500005;
struct Matrix
{
    const static int N = 5;
    const static int n = 3;
    ll x[N][N];
    void print()
    {
        for (int i=1;i<=n;++i)
        {
            for (int j=1;j<=n;++j) cout<<x[i][j]<<' ';
            cout<<endl;
        }
    }
    void clear() {memset(x,0,sizeof(x));};
    void idtt() {clear();for (int i=1;i<=n;++i) x[i][i]=1;};
    friend Matrix operator * (const Matrix a,const Matrix b)
    {
        Matrix res;
        for (int i=1;i<=n;++i)
        for (int j=1;j<=n;++j)
        {
            res.x[i][j]=0;
            for (int k=1;k<=n;++k)
            {
                res.x[i][j]=(res.x[i][j]+a.x[i][k]*b.x[k][j]);
            }
        }
        return res;
    }
}a[N],s[N];
int n,m,Q;
int main()
{
    s[0].idtt();
    cin>>n;
    for (int i=1,x,y;i<=n;++i)
    {
        scanf("%d%d",&x,&y);
        a[i].clear();
        a[i].x[1][1]=x;a[i].x[1][2]=y;a[i].x[1][3]=1;
    }
    cin>>m;
    for (int i=1,p,t;i<=m;++i)
    {
        s[i].clear();
        cin>>p;
        if (p==1)
        {
            s[i].x[1][2]=-1;s[i].x[2][1]=1;s[i].x[3][3]=1;
            continue;
        }
        if (p==2)
        {
            s[i].x[1][2]=1;s[i].x[2][1]=-1;s[i].x[3][3]=1;
            continue;
        }
        cin>>t;
        if (p==3)
        {
            s[i].x[1][1]=-1;s[i].x[2][2]=1;s[i].x[3][1]=t*2;s[i].x[3][3]=1;
            continue;
        }
        if (p==4)
        {
            s[i].x[1][1]=1;s[i].x[2][2]=-1;s[i].x[3][2]=t*2;s[i].x[3][3]=1;
            continue;
        }
        assert(0);
    }
    for (int i=1;i<=m;++i) s[i]=s[i-1]*s[i];
    cin>>Q;
    for (int cas=1,ti,id;cas<=Q;++cas)
    {
        scanf("%d%d",&ti,&id);
        Matrix t=a[id]*s[ti];
        printf("%lld %lld\n",t.x[1][1],t.x[1][2]);
    }
    return 0;
}

F

n+1个点,k个陷阱,起点为0

每轮随机从1~m中抽一个数并走这么多步,当走完后停留在陷阱上时会传送回0号点

当走到或超过n号点时结束

问期望进行几轮

考虑dp[i]为从0走到i的期望步数,从前往后推

发现非常复杂,因为有往回走的情况,dp值很难处理

再试试从后往前推,考虑dp[i]为从i走到超过或等于n的点的期望步数

假设当前在i处,是个坑

那么会被传送回0处,所以dp[i]=dp[0]

假设当前在i处,不是坑,要走到j处,分两种情况

若j不是坑: d p [ i ] = d p [ i ] + 1 m ( d p [ j ] + 1 ) dp[i]=dp[i]+\frac 1 m (dp[j]+1) dp[i]=dp[i]+m1(dp[j]+1)

若j是坑: d p [ i ] = d p [ i ] + 1 m ( d p [ 0 ] + 1 ) dp[i]=dp[i]+\frac 1 m (dp[0]+1) dp[i]=dp[i]+m1(dp[0]+1)

由于坑的dp值和0的dp值相同,所以上面两个情况可以用同一个方程

综上,若 i i i 是坑,有 d p [ i ] = d p [ 0 ] dp[i]=dp[0] dp[i]=dp[0]

i i i 不是坑,则有
d p [ i ] = 1 + 1 m ∑ j = i + 1 i + m d p [ j ] dp[i]=1+\frac 1 m \sum _{j=i+1}^{i+m} dp[j] dp[i]=1+m1j=i+1i+mdp[j]
那么问题来了,坑的dp值与0的dp值相同,但推到坑时还不知道0处的dp值是多少

考虑将 d p [ 0 ] dp[0] dp[0] 视为未知数,不影响dp过程,将所有dp值用 d p [ 0 ] ∗ x + y dp[0]*x+y dp[0]x+y 的形式代替,只记录 ( x , y ) (x,y) (x,y)

这样推到0时就会有 d p [ 0 ] = d p [ 0 ] ∗ x + y dp[0]=dp[0]*x+y dp[0]=dp[0]x+y ,解方程即可

#include <bits/stdc++.h>
using namespace std;
typedef long double ldb;
#define pb push_back
const int N = 1500005;
struct pldld
{
    ldb x,y;
    friend pldld operator + (const pldld x,const ldb y)
    {
        return {x.x,x.y+y};
    }
    friend pldld operator + (const pldld x,const pldld y)
    {
        return {x.x+y.x,x.y+y.y};
    }
    friend pldld operator - (const pldld x,const pldld y)
    {
        return {x.x-y.x,x.y-y.y};
    }
    friend pldld operator / (const pldld x,const ldb y)
    {
        return {x.x/y,x.y/y};
    }
}dp[N],s[N];
int a[N],flag[N];
int n,m,k;
int main()
{
    cin>>n>>m>>k;
    for (int i=1;i<=k;++i) cin>>a[i],flag[a[i]]=1;
    for (int i=n-1;i>=0;--i)
    {
        if (flag[i]) dp[i]={1,0};else
        {
            dp[i]=((s[i+1]-s[i+m+1])/m)+1;
        }
        s[i]=s[i+1]+dp[i];
    }
    if ((1-dp[0].x)<1e-9) {puts("-1");return 0;};
    ldb ans=dp[0].y/(-dp[0].x+1);
    printf("%.10f\n",(double)ans);
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值