2017 Chinese Multi-University Training, BeihangU Contest


http://codeforces.com/gym/102253

A

用m個二進制位可以表示10^k,給定m,問k最大是多少

乘一個lg2即可

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define fo(i,l,r) for(int i = l;i <= r;i++)
#define ll long long
using namespace std;
const int maxn = 300050;
int n;
int main(){
    int T,i=0;
    double m;
    while(scanf("%lf",&m)!=EOF){
        i++;
        m = m*log(2)/log(10);
        printf("Case #%d: %d\n",i,(int)floor(m));
    }
    return 0;
}
View Code

K

一個1-n的序列,每次選一個最小的放進暫存區,當暫存區有n-1個數時,下一次取數后把這n-1個數再放回序列,問第k次取的是多少

推出一個規律:第一次一定是全部取一遍,之后每次都有一個取不到進行下一輪循環,這個取不到的數是最大的和次大的交替出現

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define fo(i,l,r) for(int i = l;i <= r;i++)
#define ll long long
using namespace std;
const int maxn = 300050;
ll n,k;
int main(){
    int i = 0;
    while(scanf("%I64d%I64d",&n,&k)!=EOF){
        printf("Case #%d: ",++i);
        if(k<=n){
            printf("%I64d\n",k);
        }else{
            k-=2;
            ll r=k/(n-1);
            ll tmp=1ll+(k%(n-1));
            if(tmp==n-1)tmp+=((r+1)%2);
            printf("%I64d\n",tmp);
        }
    }
    return 0;
}
View Code

B

將一些字母串轉換為26進制的數字,每個字母對應一個數字,要求這些字母轉換成數后和最大,並且不能包含前導零

分開每個字母計算貢獻,然后排序。因為數字較大,需要自己動計算進位、比較大小

因為不能包含前導零,如果根據排序結果,分配到0的字母對應的是前導零,就需要找到一個不是零的字母,然后不斷往后換。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define fo(i,l,r) for(int i = l;i <= r;i++)
#define ll long long
using namespace std;
const int maxn = 100150;
const ll mod = 1e9+7;
int n;
char s[maxn];
ll val[50];
bool isZero[50];
struct dat{
    ll val;
    ll ss[maxn];
    int len;
    bool zo;
    bool operator < (const dat& b) const{
            for(int i = maxn-1;i>=1;i--){
                if(ss[i]!=b.ss[i])return ss[i]>b.ss[i];
            }
        
        return ss[1]>b.ss[1];
    }
}dats[26];
int main(){
    ios::sync_with_stdio(false);
    int T = 0;
    while(cin>>n){
        memset(val,0,sizeof(val));
        memset(isZero,false,sizeof(isZero));
        for(int i = 0;i <= 25;i++){
            memset(dats[i].ss,0,sizeof(dats[i].ss));
            dats[i].len=0;
            dats[i].val=0;
            dats[i].zo=false;
        }
        for(int j = 1;j <= n;j++) {
            cin>>(s+1);
            int l = strlen(s + 1);
            if(l>1)dats[s[1]-'a'].zo=true;
            for (int i = l; i >= 1; i--) {
                dats[s[i]-'a'].ss[l-i+1]++;
                int t = l-i+1;
                while(dats[s[i]-'a'].ss[t]==26){
                    dats[s[i]-'a'].ss[t] = 0;
                    t++;
                    dats[s[i]-'a'].ss[t]++;
                }
            }
        }
        fo(i,0,25){
            for(int j = maxn-5;j>=1;j--){
                dats[i].val *= 26ll;
                dats[i].val += dats[i].ss[j];
                dats[i].val %= mod;
            }
        }
        
        sort(dats,dats+26);
        int sheep=250;
        if(dats[25].zo){
            for(int i = 24;i >= 0;i--){
                if(!dats[i].zo){
                    sheep=i;
                    break;
                }
            }
            for(int i = sheep;i < 25;i++){
                swap(dats[i],dats[i+1]);
            }
        }
        ll ans = 0;
        fo(i,0,25){
            ans = (ans + (ll)(25ll-(ll)i)*dats[i].val) % mod;
        }
        cout<<"Case #"<<++T<<": "<<ans<<endl;
    }
    return 0;
}
View Code

F

求一個n的排列A到m的排列B的映射,要求f(i)=b(f(a(i))),求方案數。

由f(i)可以推知f(a(i)),由於是排列到排列的映射,i->a(i)->a(a(i))...最終一定會回到它自身,從而形成一個環。

把這個環求出來,由上面的式子可以推知,不斷地令i=b(i),走i對應的環的長度,最終一定要等於i,1-n的每一個位置的映射值等於滿足這個條件的b(i)的數量。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#define fo(i,l,r) for(int i = l;i <= r;i++)
#define ll long long
using namespace std;
const int maxn = 100050;
const ll mod = 1e9+7;
int n,m;
int a[maxn];
int b[maxn];
int br[maxn][30];
int amt[maxn];
bool vis[maxn];
vector<int> hasApp;
bool dfs(int x,int fa,int deep){
    vis[x]=true;
    if(a[x]==fa){
        amt[deep]++;
    }else{
        dfs(a[x],fa,deep+1);
    }
}
bool canCir(int x,int y){
    int k = 0;
    int oy = y;
    while(x){
        if(x&1)y = br[y][k];
        k++;
        x >>= 1;
    }
    //cout<<x<<" "<<y<<" "<<oy<<endl;
    return oy == y;
}
int main(){
    int T = 0;
    while(scanf("%d%d",&n,&m)!=EOF){
        fo(i,0,n-1)scanf("%d",&a[i]);
        fo(i,0,m-1)scanf("%d",&b[i]);
        memset(amt,0,sizeof(amt));
        memset(vis,0,sizeof(vis));
        hasApp.clear();
        fo(i,0,m-1){
            br[b[i]][0] = i;
        }
        fo(k,1,22){
            fo(i,0,m-1){
                br[i][k] = br[br[i][k-1]][k-1];
            }
        }
        fo(i,0,n-1){
            if(!vis[i]) dfs(i,i,1);
        }
        ll ans = 1;
        fo(i,1,n){
            if(amt[i]) hasApp.push_back(i);
        }
        int sz = hasApp.size();
        for(int i = 0;i < sz;i++){
            ll ansi = 0;
            fo(j,0,m-1){
                if(canCir(hasApp[i],j)){
                    ansi++;
                }
            }
            while(amt[hasApp[i]]){
                amt[hasApp[i]]--;
                ans = (ans*ansi) % mod;
            }
        }
        printf("Case #%d: ",++T);
        printf("%I64d\n",ans);
    }
    return 0;
}
View Code

L

求1-n的排列的個數,其中第i個要求是(li,ri)的所有子區間的最小值都是pi,其他包含i的區間的最小值都不是p。

首先,如果當前考慮的區間是(l,r),則一定有一個約束是包含整個區間的,我們把這個區間對應的位置i找出來,然后遞歸他的左邊區間和右邊區間。

此時,左區間和右區間是不相關的,沒有第二個跨越這兩個區間的約束,兩個區間的答案可以用組合數計算。

如何快速找到包含整個區間的約束?將區間排序即可。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#define fo(i,l,r) for(int i = l;i <= r;i++)
#define ll long long
using namespace std;
const int maxn = 1000050;
const ll mod = 1e9+7;
inline ll read(){
    ll x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
struct seg{
    int l;
    int r;
    int p;
    friend bool operator < (seg a,seg b){
        if(a.l!=b.l) return a.l < b.l;
        return a.r > b.r;
    }
}s[maxn];
int n;
int nowpos;
ll fac[maxn];
ll inv[maxn];
ll C(ll n,ll m){
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
ll dfs(int l,int r){
    if(l != s[nowpos].l || r != s[nowpos].r) return 0;
    int mid = s[nowpos].p;
    nowpos++;
    ll ansl=1,ansr=1;
    if(l<mid) ansl = dfs(l,mid-1);
    if(r>mid) ansr = dfs(mid+1,r);
    return ansl*ansr%mod*C(r-l,mid-l)%mod;
}
int main(){
    int T = 0;
    fac[0]=fac[1]=1;
    fo(i,2,maxn-1){
        fac[i] = (fac[i-1]*i)%mod;
    }
    inv[0]=inv[1] = 1;
    fo(i,2,maxn-1){
        inv[i]=(mod-(mod/i))*inv[mod%i]%mod;
    }
    fo(i,2,maxn-1){
        inv[i] = (inv[i]*inv[i-1])%mod;
    }
    while(scanf("%d",&n)!=EOF){
        fo(i,1,n){
            s[i].p=i;
            s[i].l=read();
        }
        fo(i,1,n){
            s[i].r=read();
        }
        sort(s+1,s+1+n);
        nowpos=1;
        ll ans=dfs(1,n);
        printf("Case #%d: ",++T);
        printf("%I64d\n",ans);
    }
    return 0;
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM