Codeforces Round #502 ( Div. 1 + Div. 2)

A.The Rank

手速题,给你一堆人的成绩,问你其中第一个人的总分排第几(总分相同按出现顺序排)。

那保存第一个人的成绩,先放在第一名,然后后面每有一个成绩比他高的,排名就加一。最后复杂度是O(n)。

我手贱,打了个结构体,大家就当没看见。

struct stu
{
    int id,a,b,c,d;
 } s[1005];

 bool operator > (stu x,stu y)
 {
    if(x.a+x.b+x.c+x.d>y.a+y.b+y.c+y.d)return 1;
    return 0;
 }

 int main()
 {
    int n,ans;
    cin>>n;
    ans=1;
    stu smith;
    cin>>smith.a>>smith.b>>smith.c>>smith.d;
    for(int i=1;i<n;i++)
    {
        stu tmp;
        cin>>tmp.a>>tmp.b>>tmp.c>>tmp.d;
        if(tmp>smith)ans++;
     }
     cout<<ans;
     return 0;
 }

B.The Bits

给你一个长度为n的01串a,再给你一个等长的01串b。然后我们有一个c=a&b。现在我们可以把a中任意两个字符交换位置,得到a’,有c’=a’&b。问有多少种换法,使得c’!=c。

因为数据范围是1e5,如果穷举的话,也就1e10,还是有几率可以过的嘛。但是我们很快发现这道题有很强的相似性,对于a,b在同一个位置上的数,总共只有四种状态,即:

○ A B
① 0 0
② 0 1
③ 1 0
④ 1 1

因为我们只能互换a中的数字,那么总共有C(4,2)种可能的换法。穷举之后发现①③,①④,②③中的A交换以后会改变,而其他换法不会改变。所以我们只要统计四种状态分别的个数,最后结果就是① * ③ + ① * ④ + ② * ③。

int main()
{
    int n;
    string a,b;
    long long cnt1=0,cnt2=0,cnt3=0,cnt4=0;
    cin>>n>>a>>b;
    for(int i=0;i<n;i++)
    {
        if(a[i]=='0'&&b[i]=='0')cnt1++;
        if(a[i]=='0'&&b[i]=='1')cnt2++;
        if(a[i]=='1'&&b[i]=='0')cnt3++;
        if(a[i]=='1'&&b[i]=='1')cnt4++;
    }
    cout<<(cnt1*cnt3+cnt1*cnt4+cnt2*cnt3)<<endl;
    return 0;
 } 

C.The Phone number

让你求一个N的全排列,使它的最长上升子序列的长度与最长下降子序列的长度之和最小。

我的直觉告诉我,分块。。。

(其实我一开始是中间切开做的,后来被大佬提醒才对了,太真实了)

那反正就是取q=sqrt(n),把n切成尽量等长的q个小段,然后。。比较难解释,举个例子,比如n=13,那么q=3。我们把它切成长度为4,4,5的三段,然后:

4 3 2 1 / 8 7 6 5 /13 12 11 10 9

这样上升子序列的长度是3(大段个数),下降子序列长度是5(小段长度的最大值),结果就是8。证明的话,我没想到特别严谨的证明,就希望有大佬提供思路。本蒻简陋证明如下:

首先,根据上面的构造法,我们得到的答案大小为q+(n+q-1)/q,记为M,我们假设存在一个比它更小的答案m。

我们考虑一个长度为n-1的以及排好的全排列,然后向里面插入一个n。可以证明,如果放在第一个,那么所有原来的下降序列长度+1;如果在最后一个,那么所有原来的上升序列长度+1;如果再中间,那么就使左边的上升序列长度+1,右边的下降序列长度+1。

n==1时,答案为2(1+1)。

对于每一次操作,若放在最左或最右,必定使答案+1。那么最终答案是n+1。

而若是放在中间,我们把两边的撇开,里面是一个类似的问题。然后通过某种玄学的方法,我们可以认为最终结果应该是和sqrt(n)有关的一个数,也就是分块的结果。

int main()
{
    int n;
    cin>>n;
    int p=sqrt(n),q=n/p;
    int cnt=q;
    for(int i=0;i<p;i++)
    {
        for(int j=0;j<q;j++)
        {
            cout<<cnt<<" ";
            cnt--;
        }
        cnt+=2*q;
    }
    if(p*q<n)for(int i=n;i>p*q;i--)cout<<i<<" ";
    return 0;
}

D.The Wu

这是一道比较复杂的模拟题,难度不大,关键在于位运算和预处理。
http://codeforces.com/contest/1017/problem/D

void read(int &x)
{
    x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return;
}

int bitread()
{
    int base=1;
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){ch=getchar();}
    while(ch>='0'&&ch<='9')
    {
        if(ch=='1')x+=base;
        ch=getchar();
        base=base*2;
    }
    return x;
}

int lowbit(int x)
{
    return x&-x;
}

int w[4100];
int cnt[4100];
int ans[4100][105]; 
int n,m,q;
int N;

int lazy_tag[105];

int main()
{
    memset(cnt,0,sizeof(cnt));
    memset(ans,0,sizeof(ans));
    read(n);read(m);read(q);
    N=1<<n;
    for(int i=0;i<n;i++)read(w[1<<i]);
    for(int i=0;i<((N));i++)
    {
        int sum=0;
        int t=i;
        while(t)
        {
            int lb=lowbit(t);
            sum+=w[lb];
            t-=lb;
        }
        w[i]=sum;
    }
    for(int i=0;i<m;i++)cnt[bitread()]++;

    for(int i=0;i<((N));i++)
    {
        memset(lazy_tag,0,sizeof(lazy_tag));
        for(int j=0;j<((N));j++)
        {
            int b=i^j^((N)-1);
            if(w[b]>100)continue;
            lazy_tag[w[b]]+=cnt[j];
    //      for(int k=w[b];k<=100;k++)ans[i][k]+=cnt[j];
        }
        int summ=0;
        for(int hh=0;hh<=100;hh++)
        {
            summ+=lazy_tag[hh];
            ans[i][hh]+=summ;
        }
    }

    while(q--)
    {
        int aa,bb;
        aa=bitread();
        read(bb);
        cout<<ans[aa][bb]<<endl;    
    }
}

猜你喜欢

转载自blog.csdn.net/qq_42778110/article/details/81541849