百度之星2016初賽(第二場) -- Astar Round2B

1003

  簽到題,其實就是輸出一個取模後的組合數,需要用到乘法逆元。

#include <iostream>    
#include <stdio.h>    
#include <cmath>    
#include <algorithm>    
#include <string>  
#include <string.h> 
#include <set>    
#include <vector>    
#include <queue>    
#include <stack>
#include <map>

using namespace std;

#define ll long long

ll mod=1e9+7;  

ll c[1010];  

//擴展歐幾里德   
void ExEuclid(ll a,ll b,ll &x,ll &y,ll &q){    
    if(b==0){    
        x=1;y=0;q=a;    
        return;    
    }    
    ExEuclid(b,a%b,y,x,q);    
    y-=x*(a/b);    
}    

//乘法逆元   
ll inv(ll num){    
    ll x,y,q;    
    ExEuclid(num,mod,x,y,q);    
    if(q==1)return (x+mod)%mod;    
}  

ll fab[1000010];  

//組合數   
ll C(ll n,ll k){  
    ll res=fab[n]*inv(fab[k]);  
    res%=mod;  
    res*=inv(fab[n-k]);  
    res%=mod;  
    return res;  
}  

int main(){
    fab[0]=1;  
    for(int i=1;i<=1000000;i++){  
        fab[i]=fab[i-1]*i;  
        fab[i]%=mod;  
    }  

    int n,m;
    while(cin>>n>>m){
        int N=n+m-4;
        int K=min(n,m)-2;
        cout<<C(N,K)<<endl;
    }
    return 0;
}

1006

  由於每個數均不相等,枚舉ai ,統計它作爲中位數有多少種情況。方法是從下標i 開始先往前掃一遍,得到每個前綴比ai 大的數-比ai 小的數有多少個,記錄在一個數組裏;然後再從下標i 開始往後掃一遍,得到後綴的情況,與前綴尋求互補。

#include <iostream>    
#include <stdio.h>    
#include <cmath>    
#include <algorithm>    
#include <string>  
#include <string.h> 
#include <set>    
#include <vector>    
#include <queue>    
#include <stack>
#include <map>

using namespace std;

#define ll long long

int a[8010];
int ans[8010];

int tmp[16010];

int main(){
    int n;
    while(cin>>n){
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        memset(ans,0,sizeof(ans)); 

        for(int i=1;i<=n;i++){
            memset(tmp,0,sizeof(tmp));

            int delta = 0;
            for(int j=i;j>=1;j--){
                if(a[j]>a[i]){
                    delta++;
                }else if(a[j]<a[i]){
                    delta--;
                }
                tmp[8000+delta]++;
            }

            delta = 0;
            for(int j=i;j<=n;j++){
                if(a[j]>a[i]){
                    delta++;
                }else if(a[j]<a[i]){
                    delta--;
                }
                ans[i] += tmp[8000-delta];
            }
        }

        for(int i=1;i<=n;i++){
            printf("%d",ans[i]); 
            if(i<n){
                printf(" ");
            }else{
                printf("\n");
            }
        }
    }
    return 0;
}

1005

  數據結構題。枚舉每個ai 作爲最終k 個區間交的左端點,二分搜右端點可以到達的最遠位置。需要對區間左端點升序排序,把左端點合法的區間納入考慮範圍,並用樹狀數組維護它們的右端點。複雜度O(nlog2(n))

#include <iostream>    
#include <stdio.h>    
#include <cmath>    
#include <algorithm>    
#include <string>  
#include <string.h> 
#include <set>    
#include <vector>    
#include <queue>    
#include <stack>
#include <map>

using namespace std;

#define ll long long

int a[100010];
ll preSum[100010];

struct Seg{
    int l,r;
    bool operator<(const Seg &other)const{
        return l<other.l;
    }
}segs[100010];

int c[100010];

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

int n,k,m;

void update(int pos){
    while(pos<=n){
        c[pos]++;
        pos+=lowbit(pos);
    }
}

int query(int pos){
    int res = 0;
    while(pos){
        res+=c[pos];
        pos-=lowbit(pos);
    }
    return res;
}

void init(){
    memset(c,0,sizeof(c));
}

int main(){
    while(cin>>n>>k>>m){
        init();
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }

        for(int i=1;i<=n;i++){
            preSum[i] = preSum[i-1] + a[i];
        }

        for(int i=1;i<=m;i++){
            scanf("%d%d",&segs[i].l,&segs[i].r);
        }

        sort(segs+1,segs+m+1);

        //枚舉
        int K=1; 
        ll ans = 0;
        for(int i=1;i<=n;i++){
            while(K<=m && segs[K].l<=i){
                update(segs[K].r);
                K++;
            }
            int l = i;
            int r = n;
            int mid;
            int res = -1;
            while(l<=r){
                mid = (l+r)>>1;
                int cnt = query(n) - query(mid-1);
                if(cnt>=k){
                    l=mid+1;
                    res = mid;
                }else{
                    r=mid-1;
                }
            }
            if(res!=-1){
                ans = max(ans,preSum[res]-preSum[i-1]);
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

1001

  題目特意強調了數據隨機(不然就做不了了)。。方法是枚舉每個ai 作爲區間最大值,同時向左右拓展,直到左右都比ai 大或者到達邊界,更新每個長度的最大價值。此題解題依據爲玄學(實際上覆雜度一定不會超過O(nlog(n)) )。
  下面強行用數學解釋一下玄學。先考慮最大的數,枚舉到這個數時一定會拓展到左右邊界才停止,也就是擴展n 次。對於第二大的數,平均情形下,只會擴展n/2 次;第三大的數平均擴展n/3 次。於是我們可以根據調和級數得到nlog(n) 的複雜度。這和快速排序很像,平均O(nlog(n)) ,最壞情形O(n2)

#include <iostream>    
#include <stdio.h>    
#include <cmath>    
#include <algorithm>    
#include <string>  
#include <string.h> 
#include <set>    
#include <vector>    
#include <queue>    
#include <stack>
#include <map>

using namespace std;

#define ll long long


ll a[100010];

ll ans[100010];

int main(){

    int n;
    while(cin>>n){
        memset(ans,0,sizeof(ans));

        for(int i=1;i<=n;i++){
            scanf("%I64d",&a[i]);
            ans[1] = max(ans[1],a[i]*a[i]);
        }

        for(int i=1;i<=n;i++){
            int l=i;
            int r=i;
            int len = 1;
            int MIN = a[i];
            while(l>1 || r<n){

                if(a[l-1]>a[i] && a[r+1]>a[i]){
                    break;
                }
                len++;
                if(a[l-1]>a[i] && r<n || (l==1 && a[r+1]<=a[i])){
                    r++;
                    if(a[r]<MIN){
                        MIN=a[r];
                    }
                }else if(a[r+1]>a[i] && l>1 || (r==n && a[l-1]<=a[i])){
                    l--;
                    if(a[l]<MIN){
                        MIN=a[l];
                    }
                }else if(l>1 && r<n && a[l-1]<=a[i] && a[r+1]<=a[i]){
                    if(a[l-1]>a[r+1]){
                        l--;
                        if(a[l]<MIN){
                            MIN=a[l];
                        }
                    }else{
                        r++;
                        if(a[r]<MIN){
                            MIN=a[r];
                        }
                    }
                }else{
                    break;
                }
                ans[len] = max(ans[len],a[i]*MIN);
            }
        }

        for(int i=1;i<=n;i++){
            printf("%I64d\n",ans[i]);
        }

    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章