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\n",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\n",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\n",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\n",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\n",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\n",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\n",a,c);
    else
    {
        printf("%c %c\n",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\n",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

 

posted @ 2019-02-04 19:57  nimphy  阅读(90)  评论(0编辑  收藏