7.10

CF380C Sereja and Brackets

题意:

  给一个只有左右括号的序列和n段区间,求每个序列区间中最长的匹配括号子序列的长度。

思路:

  线段树,记录每个区间中未匹配的左括号的未匹配的右括号的个数,寻找区间是都是从左往右找,最后答案就是区间长度-1-未匹配的左右括号个数

code:

#include<cstdio>
#define N 1000000
using namespace std;
struct arr{
    int l,r,a,b;
}tr[N*4];
int ri,le,n,l;
char s[N];
void build(int w,int l,int r){
    tr[w].l=l,tr[w].r=r;
    if (l==r){
        if (s[l-1]=='(') tr[w].a++;
        else tr[w].b++;
        return;
    }
    int mid=(l+r)/2;
    build(w*2,l,mid);
    build(w*2+1,mid+1,r);
    tr[w].a=tr[w*2+1].a;
    tr[w].b=tr[w*2].b;
    if (tr[w*2].a>tr[w*2+1].b)
        tr[w].a+=(tr[w*2].a-tr[w*2+1].b);
    else tr[w].b+=(tr[w*2+1].b-tr[w*2].a);
}
void find(int w,int l,int r){
    if (tr[w].l==l&&tr[w].r==r){
        if (tr[w].b<=le) le-=tr[w].b;
        else ri+=tr[w].b-le,le=0;
        le+=tr[w].a;
        return;
    }
    int mid=(tr[w].l+tr[w].r)/2;
    if (r<=mid) find(w*2,l,r);
    else if (l>mid) find(w*2+1,l,r);
    else{
        find(w*2,l,mid);
        find(w*2+1,mid+1,r); 
    }
}
int main(){
    scanf("%s",&s);
    for (l=0;s[l]!='\0';l++);
    build(1,1,l);
    scanf("%d",&n);
    for (int i=1;i<=n;i++){
        int x,y;
        le=ri=0;
        scanf("%d%d",&x,&y);
        find(1,x,y);
        printf("%d\n",y-x+1-le-ri);
    }
} 

 

CF1366D Two Divisors

题意:

  给出n个数字,判断每个数字a是否存在两个因数d1>1和d2>1,满足gcd(d1+d2,a)=1,没有则输出两个-1

思路:

  每个数字都可以分成p1^k1*p2^k2*p3^k3... (p1<p2<p3...)

  则a的因数有a/(p1^k1)和p1,则a/(p1^k1)+p1与p1,p2,p3任何一个都互质

code:

#include<cstdio>
#include<algorithm>
#define N 10000000
using namespace std;
int s[N+7],n,a[N+7],b[N+7];
bool f[N+7];
int main(){
    for (int i=1;i<=N;i++)
        s[i]=i;
    for (int i=2;i<=N;i++)
        if (!f[i])
            for (int j=2;j<=N/i;j++){
                f[i*j]=true;
                s[i*j]=min(s[i*j],i);
            }
    scanf("%d",&n);
    for (int i=1;i<=n;i++){
        int x,y;
        scanf("%d",&x);
        y=x;
        a[i]=b[i]=1;
        while ((x%s[y])==0){
            a[i]*=s[y];
            x/=s[y];
        }
        if (x==1)
            a[i]=b[i]=-1;
        else b[i]=x;
    }
    for (int i=1;i<=n;i++)
        printf("%d ",a[i]);
    printf("\n");
    for (int i=1;i<=n;i++)
        printf("%d ",b[i]);
}

 

CF1370D Odd-Even Subsequence

题意:

  给出一个长度为n序列,你可以将序列删剩m个数字,使得奇数位置的最大值和偶数位置的最大值的最小值最小。

题意:

  这种题目求最大值最小的可以考虑二分,判断能否简洁的取到m/2个不大于mid的值,还要考虑m的奇偶。

code:

#include<cstdio>
#include<algorithm>
#define N 200007
using namespace std;
int n,m,ma,a[N],l,r,mid;
bool check1(int x){
    int p=0;
    if (m%2==1)
        for (int i=2;i<n;i++){
            if (a[i]<=x) p++,i++;
        }
    else
        for (int i=2;i<=n;i++){
            if (a[i]<=x) p++,i++;
        }
    if (p>=m/2) return true;
    return false;
}
bool check2(int x){
    int p=0;
    if (m%2==1)
        for (int i=1;i<=n;i++){
            if (a[i]<=x) p++,i++;
        }
    else
        for (int i=1;i<n;i++){
            if (a[i]<=x) p++,i++;
        }
    if (p>=(m+1)/2) return true;
    return false;
}
int main(){
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        r=max(a[i],r);
    }
    l=1;
    while (l<r){
        mid=(l+r)/2;
        if (check1(mid)||check2(mid))
            r=mid;
        else l=mid+1;
    }
    printf("%d\n",l);
}

 

CF2B The least round way

题意:

  给出一个n*n个矩阵,从左上角走到右上角,求路线中所有数之积结尾0的个数最少的个数,并输出路线

题意:

  结尾有0就是2*5,分别求2最少时min(2的个数,5的个数)和5最少时min(2的个数,5的个数),有一个特殊情况就是有0,如果有0且最终结果大于1,那就输出1,路线是要通过0的位置

code:

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 1007
using namespace std;
int n,a[N][N],h[N][N],t[N][N],p1[N][N],p2[N][N],c1[N][N],c2[N][N],ans;
char d1[N][N],d2[N][N],p[N*2];
void check1(){
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++){
            int x1=p1[i-1][j],y1=p1[i][j-1];
            int x2=c2[i-1][j],y2=c2[i][j-1];
            if (i==1) x1=x2=0xffffff;
            if (j==1) y1=y2=0xffffff;
            if (x1<y1||(x1==y1)&&(p2[i-1][j]<=p2[i][j-1]))
                p1[i][j]=h[i][j]+p1[i-1][j],p2[i][j]=t[i][j]+p2[i-1][j],d1[i][j]='D';
            else p1[i][j]=h[i][j]+p1[i][j-1],p2[i][j]=t[i][j]+p2[i][j-1],d1[i][j]='R';
            if (x2<y2||(x2==y2)&&(c1[i-1][j]<=c1[i][j-1]))
                c1[i][j]=h[i][j]+c1[i-1][j],c2[i][j]=t[i][j]+c2[i-1][j],d2[i][j]='D';
            else c1[i][j]=h[i][j]+c1[i][j-1],c2[i][j]=t[i][j]+c2[i][j-1],d2[i][j]='R';
        }
    int k1=min(p1[n][n],p2[n][n]),k2=min(c1[n][n],c2[n][n]);
    ans=min(k1,k2);
    int x=n,y=n;
    for (int i=2*n-2;i>=1;i--){
        if (k1<=k2) p[i]=d1[x][y];
        else p[i]=d2[x][y];
        if (p[i]=='D') x--;
        else y--;
    }
}
int main(){
    scanf("%d",&n);
    int g[50],e[30];
    g[0]=e[0]=1;
    for (int i=1;i<=26;i++)
        g[i]=g[i-1]*2;
    for (int i=1;i<=11;i++)
        e[i]=e[i-1]*5;
    bool q=false;
    int bx,by;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++){
            scanf("%d",&a[i][j]);
            if (a[i][j]==0) q=true,bx=i,by=j;
            for (int s=26;s>=0;s--)
                if (a[i][j]%g[s]==0){
                    h[i][j]=s;
                    a[i][j]/=g[s];
                    break;
                }
            for (int s=11;s>=0;s--)
                if (a[i][j]%e[s]==0){
                    t[i][j]=s;
                    a[i][j]/=e[s];
                    break;
                }
        }
    check1();
    if (q&&ans>1){
        printf("1\n");
        for (int i=1;i<bx;i++)
            printf("D");
        for (int i=1;i<n;i++)
            printf("R");
        for (int i=1;i<=n-bx;i++)
            printf("D");
        return 0;
    }
    printf("%d\n",ans);
    for (int i=1;i<=2*n-2;i++)
        printf("%c",p[i]);
    printf("\n");
} 

 

posted @ 2021-07-10 13:34  kasiruto  阅读(102)  评论(0编辑  收藏  举报