• Gym .101879 USP Try-outs (寒假自训第七场)


    B .Aesthetics in poetry

    题意:给定N个数,(N<2000 ,a[i] <=1e9),让你找一个最大的K,使得N个数膜K的余数个数全都等于N/K个。

    思路:我们找到N的因子,然后验证即可,复杂度O(N^2)

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=1000010;
    int a[maxn],N,ans=-1,num[maxn];
    void get(int k)
    {
        rep(i,0,k-1) num[i]=0;
        rep(i,1,N) num[a[i]%k]++;
        bool F=true;
        rep(i,0,k-1) if(num[i]!=N/k) F=false;
        if(!F) return ;
        if(ans==-1) ans=k;
        else ans=min(ans,k);
    }
    int main()
    {
        scanf("%d",&N);
        rep(i,1,N) scanf("%d",&a[i]);
        for(int i=2;i*i<=N;i++){
            if(N%i==0) {
                get(i);
                if(i*i!=N) get(N/i);
            }
        }
        get(N);
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    D .Maximizing Advertising

    题意:给定二维平面上N个点,其中一些是w,一些是b,让你用两个不相交的矩阵把他们圈起来,一个统计w的个数,一个统计b的个数,使得和最大。

    思路:其实就是用一根线把平面分成两个。 枚举分割线即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+5;
    struct node
    {
        int x,y,tp;
    }a[maxn];
    int n,X[maxn],Y[maxn],vis1[maxn],vis2[maxn],sum1,sum2;
    int gao(int tp,int m)
    {
        memset(vis1,0,sizeof(vis1));
        memset(vis2,0,sizeof(vis2));
        if(tp==1)
        {
            for(int i=1;i<=n;i++)
            if(a[i].tp==1)vis1[a[i].x]++;
            else vis2[a[i].x]++;
        }
        else
        {
            for(int i=1;i<=n;i++)
            if(a[i].tp==1)vis1[a[i].y]++;
            else vis2[a[i].y]++;
        }
        int ans=0,res1=0,res2=0;
        for(int i=1;i<=m;i++)
        {
            res1+=vis1[i],res2+=vis2[i];
            ans=max(ans,res1+sum2-res2);
            ans=max(ans,res2+sum1-res1);
        }
        return ans;
    }
    int main()
    {
        char c[2];
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%s",&X[i],&Y[i],c);
            if(c[0]=='b')a[i].tp=1,sum1++;
            else a[i].tp=2,sum2++;
            a[i].x=X[i],a[i].y=Y[i];
        }
        sort(X+1,X+1+n);
        int sz1=unique(X+1,X+1+n)-X-1;
        sort(Y+1,Y+1+n);
        int sz2=unique(Y+1,Y+1+n)-Y-1;
        for(int i=1;i<=n;i++)
        {
            a[i].x=lower_bound(X+1,X+1+sz1,a[i].x)-X;
            a[i].y=lower_bound(Y+1,Y+1+sz2,a[i].y)-Y;
        }
        int ans=gao(1,sz1);
        ans=max(ans,gao(2,sz2));
        printf("%d
    ",ans);
    }
    View Code

    E .Group work

    题意:给定N个人,问有多少种分组情况,满足这个组至少有两人。

    思路:即C(N,2)+C(N,3)+..C(N,N); 直接暴力即可, 也可以用2^N-C(N,1)-C(N,0);

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=110;
    ll C[maxn][maxn],ans;
    int main()
    {
        rep(i,0,40) C[i][i]=C[i][0]=1;
        rep(i,1,40)
         rep(j,1,i)
         C[i][j]=C[i-1][j]+C[i-1][j-1];
        int N; scanf("%d",&N);
        rep(i,2,N) ans+=C[N][i];
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    G .Running a penitentiary

    题意:给定N个区间[Li,Ri],然后Q次询问,每次给出a,b,问a到b这几个区间的公共长度是多少。

    思路:开始还以为要主席树找区间的公共部分,但是发现既然是a到b的区间都有,那么公共部分因为的[b的最大值,a的最小值]。所以离散一下,线段树即可。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=1000010;
    const int inf=1000000000;
    int Mx[maxn],Mn[maxn];
    void update1(int Now,int L,int R,int pos,int val)
    {
        if(L==R) { Mn[Now]=val; return ;}
        int Mid=(L+R)>>1;
        if(pos<=Mid) update1(Now<<1,L,Mid,pos,val);
        else update1(Now<<1|1,Mid+1,R,pos,val);
        Mn[Now]=min(Mn[Now<<1],Mn[Now<<1|1]);
    }
    int query1(int Now,int L,int R,int l,int r)
    {
        if(l<=L&&r>=R) return Mn[Now];
        int Mid=(L+R)>>1,res=inf;
        if(l<=Mid) res=min(res,query1(Now<<1,L,Mid,l,r));
        if(r>Mid) res=min(res,query1(Now<<1|1,Mid+1,R,l,r));
        return res;
    }
    void update2(int Now,int L,int R,int pos,int val)
    {
        if(L==R){ Mx[Now]=val;return ;}
        int Mid=(L+R)>>1;
        if(pos<=Mid) update2(Now<<1,L,Mid,pos,val);
        else update2(Now<<1|1,Mid+1,R,pos,val);
        Mx[Now]=max(Mx[Now<<1],Mx[Now<<1|1]);
    }
    int query2(int Now,int L,int R,int l,int r)
    {
        if(l<=L&&r>=R) return Mx[Now];
        int Mid=(L+R)>>1,res=-inf;
        if(l<=Mid) res=max(res,query2(Now<<1,L,Mid,l,r));
        if(r>Mid) res=max(res,query2(Now<<1|1,Mid+1,R,l,r));
        return res;
    }
    int main()
    {
        int N,M,P,L,R; char opt[4];
        scanf("%d%d",&N,&M);
        rep(i,1,N<<2) Mn[i]=inf,Mx[i]=-inf;
        rep(i,1,N){
            scanf("%d%d",&L,&R);
            update1(1,1,N,i,R);
            update2(1,1,N,i,L);
        }
        rep(i,1,M){
            scanf("%s",opt);
            if(opt[0]=='?'){
                scanf("%d%d",&L,&R);
                int mn=query1(1,1,N,L,R);
                int mx=query2(1,1,N,L,R);
                printf("%d
    ",max(mn-mx+1,0));
            }
            else {
                scanf("%d%d%d",&P,&L,&R);
                update1(1,1,N,P,R);
                update2(1,1,N,P,L);
            }
        }
        return 0;
    }
    View Code

    J .Meme Wars

    题意:字符串操作,每次F(x)=F(x-1)+'x'+F(x-1);问26次操作后,第N位是什么。(N<1000)

    思路:因为N不大,所以我们保留前面N位,模拟即可。复杂度(N^2)

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=1010;
    char c[maxn][maxn]; int L[maxn],N;
    int main()
    {
        scanf("%d",&N);
        c[1][1]='a'; L[1]=1;
        rep(i,2,27) {
            L[i]=L[i-1];
            rep(j,1,L[i]) c[i][j]=c[i-1][j];
            if(L[i]+1<=N) L[i]++,c[i][L[i]]='a'+i-1;
            rep(j,1,L[i-1]) {
                if(L[i]+1>N) break;
                c[i][++L[i]]=c[i][j];
            }
        }
        printf("%c
    ",c[27][N]);
        return 0;
    }
    View Code

    H .Wine Production

    题意:给定N个数,Q次询问,每次询问一个区间最大的x,满足至少x个不同的数出现了x次。(N,Q<3e4)

    思路:跑莫队,然后记录每个数的个数。  问题是是莫队之后怎么维护这个答案。 我们用num[i]表示i出现的次数,cnt[i]表示出现次数为i的个数。 这样很难维护到有效信息,因为每次求答案的时候还是得x=1,=2..一个一个验证。    转化一下,cnt[i]表示出现次数大于等于i的个数,就可以莫队的时候直接转移答案了。 比如我加入一个数fcy, 那么num[fcy]++; cnt[num[fcy]]++;(而不用去cnt[num[fcy]-1]--;)因为出现次数大于等于num[fcy]-1的个数没变。 而加入fcy时,答案ans可能不变,可能变成了ans++变为了, cnt[num[fcy]]; 减去一个数fcy时也一样,ans可能不变,可能--;  想象成一个栈,如果操作中间,那么每次得重新维护这个栈。 而只操作栈顶,那么有效信息最多改变1,方便我们去维护。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=1000010;
    const int inf=1000000000;
    int a[maxn],b[maxn],cnt[maxn],num[maxn];
    int ans[maxn],tot,B,res;
    struct qust{
        int l,r,id;
        bool friend operator<(qust w,qust v){
            if(w.r/B==v.r/B) return w.l<v.l;
            return w.r<v.r;
        }
    }q[maxn];
    void add(int x,int tp)
    {
        if(tp==-1){ cnt[num[x]]--; num[x]+=tp;  if(cnt[res]<res) res--;}
        else { num[x]+=tp;cnt[num[x]]++;if(cnt[num[x]]>=num[x]) res=max(res,num[x]);}
    }
    int main()
    {
        int N,M;
        scanf("%d%d",&N,&M); B=300;
        rep(i,1,N) scanf("%d",&a[i]),b[i]=a[i];
        sort(b+1,b+N+1); tot=unique(b+1,b+N+1)-(b+1);
        rep(i,1,N) a[i]=lower_bound(b+1,b+tot+1,a[i])-b;
        rep(i,1,M) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
        sort(q+1,q+M+1);
        int L=1,R=0;
        rep(i,1,M){
            while(L<q[i].l) add(a[L++],-1);
            while(L>q[i].l) add(a[--L],1);
            while(R>q[i].r) add(a[R--],-1);
            while(R<q[i].r) add(a[++R],1);
            ans[q[i].id]=res;
        }
        rep(i,1,M) printf("%d
    ",ans[i]);
        return 0;
    }
    View Code

    I .A story about tea

    题意:三个港口ABC,开始N条船在A港口一次排列,要全部到B去,而且满足船后入后出,现在让你走K步,把船全部弄到C港口,而且排列顺序和开始一样,输出方案。

    思路:就是一个汉诺塔,汉诺塔的步数是2^N-1;多余的我们可以瞎走。

    by许

    #include<bits/stdc++.h>
    using namespace std;
    int cnt=0,all,res;
    void move2(int a,int b,int c)
    {
        if(!res)printf("%c %c
    ",a,c);
        else
        {
            printf("%c %c
    ",a,b);
            res--;
            move2(b,a,c);
        }
    }
    void move(int k,char a,char b,char c)
    {
        if(!k)return;
        move(k-1,a,c,b);
        cnt++;
        if(cnt==all)
        {
            move2(a,b,c);
            return;    
        }
        printf("%c %c
    ",a,c);
        move(k-1,b,a,c);
    }
    int main()
    {
        int n,k;
        scanf("%d%d",&n,&k);
        if(k<(1<<n)-1)puts("N");
        else
        {
            puts("Y");
            all=(1<<n)-1;
            res=k-all;
            move(n,'A','B','C');
        }
           return 0;
    }
    View Code
  • 相关阅读:
    ASP.NET(C#)——唯一订单号
    Oracle——备份与还原
    ASP.NET(C#)——日期函数
    数据安全——数据安全标准
    文件内容的追加
    文件的读取
    创建文件,写文件
    遍历文件改进
    遍历文件夹
    递归方法求前n项和
  • 原文地址:https://www.cnblogs.com/hua-dong/p/10352083.html
Copyright © 2020-2023  润新知