1. 程式人生 > >Codeforces Round #312 (Div. 2) (第三題是位運算,好題)

Codeforces Round #312 (Div. 2) (第三題是位運算,好題)

分析:從0座標分開,負半軸一個數組,正半軸一個數組,來記錄果樹的左邊和數量,可以用結構體陣列來儲存資料,其中少的一個半軸上的果樹肯定會全被採光,而多的一邊樹上會多采一棵樹。
struct p{
int num,x;
}
p neg[105],pos[105];
這樣表示更容易排序,用一個sort就可以了,我下邊的程式碼用的是冒泡,稍微麻煩點
#include<bits/stdc++.h>
using namespace std;
int n;
int pos[100],neg[100],posflag[100],negflag[100];
int main()
{
    scanf("%d",&n);
    int x,a,numpos=0,numneg=0;
    for(int i=0;i<n;i++){
        scanf("%d%d",&x,&a);
        if(x>0){posflag[numpos]=x;pos[numpos++]=a;}
        else {negflag[numneg]=x;neg[numneg++]=a;}
    }
    int sum=0;
    if(numpos>numneg){
        for(int ii=0;ii<numpos-1;ii++)
        for(int j=0;j<numpos-1-ii;j++){
            if(posflag[j]>posflag[j+1]){
                int t=posflag[j];posflag[j]=posflag[j+1];posflag[j+1]=t;
                t=pos[j];pos[j]=pos[j+1];pos[j+1]=t;
            }
        }
        for(int i=0;i<numneg;i++){
            sum+=pos[i]+neg[i];
        }
        sum+=pos[numneg];
    }
    else if(numpos<numneg){
        for(int ii=0;ii<numneg-1;ii++)
        for(int j=0;j<numneg-ii-1;j++){
            if(negflag[j]<negflag[j+1]){
                int t=negflag[j];negflag[j]=negflag[j+1];negflag[j+1]=t;
                t=neg[j];neg[j]=neg[j+1];neg[j+1]=t;
            }
        }
        for(int i=0;i<numpos;i++)
            sum+=pos[i]+neg[i];
        sum+=neg[numpos];
    }
    else {
        for(int i=0;i<numpos;i++)
            sum+=pos[i]+neg[i];
    }

      printf("%d\n",sum);
      return 0;
}

題意:找出一個數組中出現次數最多而且包含數最少(即最大小標—最小下標最小)的數

分析:如下程式碼所示,構造一個結構體陣列來儲存每個點的資訊,然後排序處理一下OK

#include<bits/stdc++.h>
using namespace std;
struct p
{
    int count=0,first,last;
    bool flag=0;
}num[1000005];
int n,a;
bool cmp(p a,p b)
{
    if(a.count<b.count)return true;
    else if(a.count>b.count) return false;
    return (a.last-a.first)>(b.last-b.first);
}
int main()
{
    scanf("%d",&n);
    int maxa=1;
    for(int i=1;i<=n;i++){
        scanf("%d",&a);
        if(num[a].flag){
            num[a].last=i;
            num[a].count++;
        }
        else{
            num[a].count++;
            num[a].first=i;
            num[a].flag=1;
        }
        if(maxa<a)maxa=a;
    }
    sort(num+1,num+maxa+1,cmp);
    if(num[maxa].first==0||num[maxa].last==0)cout<<"1 1"<<endl;//如果全都
    else
    cout<<num[maxa].first<<' '<<num[maxa].last<<endl;
    return 0;
}

題意:n個數字,對每個數字可以進行兩種操作:num*2與num/2(向下取整),求:讓n個數相等最少需要操作多少次

分析:*2和/2,接容易發現可以用移位操作完成,那麼可以列舉每個數字可以到達的數字並且記錄下所需要的操作步數,最後統計每個數字vis出現次數為n,並且操作步數最小的數。因為奇數/2,向下取整,所以如果是奇數還可以/2*2,,來到達不同的數字

比較詳細的分析:here

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
int num[(int)1e5+5],vis[(int)1e5+5];
void solve(int val)
{
    int t=val<<1,step=1;
    while(t<=(int)1e5){
        vis[t]++;
        num[t]+=step;
        step++;
        t<<=1;
    }
    t=val,step=0;
    while(t>0){
        vis[t]++;
        num[t]+=step;
        if((t&1)&&t>1){
            int tt=t/2*2,tstep=step+2;
            while(tt<=(int)1e5){
                vis[tt]++;
                num[tt]+=tstep;
                tt<<=1;
                tstep++;
            }
        }
        step++;
        t>>=1;
    }
}
int main()
{
    int n,val;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&val);
        solve(val);
    }
    int ans=INF;
    for(int i=1;i<=(int)1e5;i++){
        if(vis[i]==n)
            ans=min(ans,num[i]);
    }
    printf("%d\n",ans);
}