codeforces 1150(round 556 Div.2)E - Tree Generator™

A. Stock Arbitraging
签到

#include
using namespace std;
int a[35],b[35];
int main()
{
    int n,m,r;
    scanf("%d%d%d",&n,&m,&r);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int j=1;j<=m;j++)
        scanf("%d",&b[j]);
    sort(a+1,a+1+n);
    sort(b+1,b+1+m);
    reverse(b+1,b+1+m);
    int t=b[1];
    int ans=r;
    if(a[1]=2)
    for(int i=0;a[1]*i<=r;i++)
            ans=max(ans,(r-a[1]*i)/a[2]*t+(r-a[1]*i)%a[2]+i*t);
    printf("%d\n",ans);
}

B - Tiling Challenge
很明显当左上边界有空的你就必须要填,所以直接从左上开始碰到空的就填就行

#include
using namespace std;
char a[55][55];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%s",a[i]+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
    {
        if(a[i][j]=='.'&&a[i-1][j]=='.'&&a[i+1][j]=='.'&&a[i][j-1]=='.'&&a[i][j+1]=='.')
        {
            a[i][j]=a[i-1][j]=a[i+1][j]=a[i][j-1]=a[i][j+1]='#';
        }
    }
    bool flag=true;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        if(a[i][j]=='.') flag=false;
    printf(flag?"YES":"NO");
}

C - Prefix Sum Primes
贪心的能用2就用2,因为1可以保证你能够覆盖到其它质数

#include
using namespace std;
int n,a,b,sum;
vectorv;
bool vis[400005];
queueq;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        if(x==1) a++;
        else b++;
        sum+=x;
    }
    int now=0;
    for(int i=2;i<=sum;i++)
    {
        if(!vis[i])
        {
            v.push_back(i);
            for(int j=i;j<=sum;j+=i)
                vis[j]=true;
        }
    }
    int ans=0;
    for(int i=0;i0)
        {
            a--,t--,now++,ans++;
            q.push(1);
            if(b>=t/2)
            {
                for(int j=1;j<=t/2;j++)
                    q.push(2);
                b-=t/2,t=0;
            }
            else
            {

                t-=2*b;
                for(int j=1;j<=b;j++)
                    q.push(2);
                b=0;
                a-=t;
                for(int j=1;j<=t;j++)
                    q.push(1);
                t=0;
            }
            now=v[i];
        }
        else if(t%2==0)
        {
            ans++;
            if(b>=t/2)
            {
                for(int j=1;j<=t/2;j++)
                    q.push(2);
                b-=t/2,t=0;

            }else
            {
              t-=2*b;

              for(int j=1;j<=b;j++)
                    q.push(2);b=0;
                    for(int j=1;j<=t;j++)
                    q.push(1);
                    a-=t,t=0;
            }
            now=v[i];
        }
    }
    while(a>0) q.push(1),a--;
    while(b>0) q.push(2),b--;
    while(!q.empty())
    {
        printf("%d ",q.front());q.pop();
    }
}

D - Three Religions
设dp[i][j][k]表示第一个串匹配到i,第二个串匹配到j,第三个串匹配到k的最小位置,每次插入一个字符后,直接去更新另外两维dp即可

#include
#define inf 0x3f3f3f3f
using namespace std;
int n,m,c1,c2,c3,p[26],nex[100005][26],dp[255][255][255];
char s[100005];
int a[4][255];
void Min(int &x,int y)
{
    if(x==-1) x=y;
    else x=min(x,y);
}
void up(int i,int j,int k)
{
    int x=a[1][i],y=a[2][j],z=a[3][k];
    dp[i][j][k]=-1;
    if(i!=0&&dp[i-1][j][k]!=-1)
    {
        int t=dp[i-1][j][k];
        t=nex[t][x];
        if(t!=-1)
            Min(dp[i][j][k],t);
    }
    if(j!=0&&dp[i][j-1][k]!=-1)
    {
        int t=dp[i][j-1][k];
        t=nex[t][y];
        if(t!=-1)
            Min(dp[i][j][k],t);
    }
    if(k!=0&&dp[i][j][k-1]!=-1)
    {
        int t=dp[i][j][k-1];
        t=nex[t][z];
        if(t!=-1)
            Min(dp[i][j][k],t);
    }
}
void up1()
{
    for(int i=0;i<=c2;i++)
        for(int j=0;j<=c3;j++)
        up(c1,i,j);
}
void up2()
{
    for(int i=0;i<=c1;i++)
        for(int j=0;j<=c3;j++)
        up(i,c2,j);
}
void up3()
{
    for(int i=0;i<=c1;i++)
        for(int j=0;j<=c2;j++)
        up(i,j,c3);
}
int main()
{
    scanf("%d%d",&n,&m);
    scanf("%s",s+1);
    memset(p,-1,sizeof(p));
    for(int i=n;i>=0;i--)
    {
        for(int j=0;j<26;j++)
            nex[i][j]=p[j];
        if(i==0) break;
        p[s[i]-'a']=i;
    }
    memset(dp,-1,sizeof(dp));
    dp[0][0][0]=0;
    while(m--)
    {
        char opt[5],c[5];
        int id;
        scanf("%s%d",opt,&id);
        if(opt[0]=='+')
        {
            scanf("%s",c);
            if(id==1)
                a[id][++c1]=c[0]-'a',up1();
            else if(id==2)
                a[id][++c2]=c[0]-'a',up2();
            else a[id][++c3]=c[0]-'a',up3();
        }
        else
        {
            if(id==1) c1--;
            else if(id==2) c2--;
            else c3--;
        }
        if(dp[c1][c2][c3]==-1)
            printf("NO\n");
        else printf("YES\n");
    }
}

E - Tree Generator™
选任意点为根,对于任意两个点a,c设u(a),u(\c)分别表示以任意点为跟时的深度,则a,c的距离d(a,c)=u(a)+u(\c)-2*u(LCA(a,c))。
我们维护用括号前缀的深度,深度=这段前缀中左括号个数-右括号个数,设LCA(a,c)=b,则u(b)满足u(b)=min(u(x)),a<=x<=c,则这样维护的时间复杂度时O(n),修改时O(n)
因此我们可以考虑用线段树维护,线段树的每一个结点维护一段括号的信息。在每个结点中我们维护以下信息:
1.深度(一段中的左括号个数-右括号个数,可能为负)
2.max(u(\c)-2*u(b))
3.max(u(a)-2*u(b))
4.min(u(b))
5.max(u(a))
6.max(u(a)-2*u(b)+u(\c))
维护这些信息后对于线段树的一个点就可以很方便通过合并它的左孩子和右孩子得到这个点应该维护的信息。
注意在对于一段区间l,r的右孩子m+1,r,右孩子的深度是以m+1处为根的(所以才有度数为负数的情况出现),因此在合并左右孩子的时候,我们需要使合并时的右孩子值为以l为根的,所以合并时的右孩子的值要加上左孩子l,m的深度。
注意合并时要满足a<=b<=c

#include
using namespace std;
const int N=2e5+5;
struct node
{
    /*
    sum depth=right-Brackets numbers- left-Brackets numbers
    rmx max(u(c)-2*u(b))
    lmx max(u(a)-2*u(b))
    mn min(u(b))
    mx max(u(a))
    d max(u(a)-2*u(b)+u(c))
    */
    int sum,rmx,lmx,mn,mx,d;
    node(int sum=0,int rmx=0,int lmx=0,int mn=0,int mx=0,int d=0):sum(sum),rmx(rmx),lmx(lmx),mn(mn),mx(mx),d(d){}
}t[4*N];
char s[N];
int n,k;
void update(int k)
{
    //sum depth=right Brackets + left Brackets
    t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
    //rmx max(u(c)-2*u(b))
    t[k].rmx=max(t[k<<1].rmx,max(t[k<<1|1].rmx-t[k<<1].sum,t[k<<1|1].mx+t[k<<1].sum-2*t[k<<1].mn));
    //lmx max(u(a)-2*u(b))
    t[k].lmx=max(t[k<<1].lmx,max(t[k<<1|1].lmx-t[k<<1].sum,t[k<<1].mx-2*(t[k<<1|1].mn+t[k<<1].sum)));
    //mn min(u(b))
    t[k].mn=min(t[k<<1].mn,t[k<<1|1].mn+t[k<<1].sum);
    //mx max(u(a))
    t[k].mx=max(t[k<<1].mx,t[k<<1|1].mx+t[k<<1].sum);
    //d max(u(a)-2*u(b)+u(c))
    t[k].d=max(max(t[k<<1].d,t[k<<1|1].d),max(t[k<<1|1].rmx-t[k<<1].sum+t[k<<1].mx,t[k<<1].lmx+t[k<<1|1].mx+t[k<<1].sum));
}
void build(int l,int r,int k)
{
    if(l==r)
    {
        int x=s[l]=='('?1:-1;
        t[k]=node(x,-x,-x,x,x,0);//u(a),u(a)-2*u(a),u(a)-2*u(a),u(a),u(a),u(a)-2*u(a)+u(a)
        return;
    }
    int m=l+r>>1;
    build(l,m,k<<1);
    build(m+1,r,k<<1|1);
    update(k);
}
void fix(int l,int r,int k,int x)
{
    if(l==r)
    {
        build(l,r,k);
        return;
    }
    int m=l+r>>1;
    if(x<=m) fix(l,m,k<<1,x);
    else fix(m+1,r,k<<1|1,x);
    update(k);
}
int main()
{
    scanf("%d%d",&n,&k);
    scanf("%s",s+1);
    n=n*2-2;
    build(1,n,1);
    printf("%d\n",t[1].d);
    for(int i=1;i<=k;i++)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        swap(s[l],s[r]);
        fix(1,n,1,l);
        fix(1,n,1,r);
        printf("%d\n",t[1].d);
    }
}

你可能感兴趣的:(codeforces 1150(round 556 Div.2)E - Tree Generator™)