2017BNUZCPC

菜就要多補題。。

A 大仙買貢茶

題目大意:
現在有有n杯偶數價格的貢茶,每兩杯貢茶將會選擇其中價格最低的貢茶進行半價,問最少花多少錢可以買完所有貢茶。

題解:
水題。sort一下。每次兩位兩位挪動,第二位的減半即可。

/*
@resources: BNUZCPC A
@date: 2017-5-14
@author: QuanQqqqq
@algorithm: yy
*/
#include <bits/stdc++.h>
#define MAXN 1005

using namespace std;

int num[MAXN];

int main(){
    int T,n,cas = 1;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        int ans = 0;
        for(int i = 0;i < n;i++){
            scanf("%d",&num[i]);
            ans += num[i];
        }
        sort(num,num + n);
        for(int i = n - 1;i >= 1;i -= 2){
            ans -= num[i - 1] / 2;  
        }
        printf("Case #%d: %d\n",cas++,ans);
    }
}

B 麗澤湖毒素

題目大意:
交互式判題,每次機器先告訴你有m瓶酒,然後要你限定在10只老鼠的情況下,告訴機器應該讓他們如何喝酒,然後機器會告訴你有多少隻老鼠死了和他們的編號,最後你要告訴機器,答案是什麼。

題解:
10只老鼠,2的10次方是1024,可以用二進制表示來模擬老鼠喝酒,先告訴機器n批老鼠,第i批所使用的老鼠是i的二進制數所對應的位置,最終得到死亡的老鼠再轉回10進制就是所需的答案。
比賽的時候wa在空格上orz。。。

/*
@resources: BNUZCPC B
@date: 2017-5-14
@author: QuanQqqqq
@algorithm: yy
*/
#include <bits/stdc++.h>

using namespace std;

int main(){
    string str;
    int n;
    while(cin >> n >> str >> str >> str){
        for(int i = 1;i <= n;i++){
            int p = i;
            int total = 0;
            while(p){
                if(p & 1){
                    total++;
                }
                p >>= 1;
            }
            printf("%d",total);
            fflush(stdout);
            int tmp = i,idx = 1;
            while(tmp){
                if(tmp & 1){
                    printf(" %d",idx);
                    fflush(stdout);
                }
                idx++;
                tmp >>= 1;
            }
            printf("\n");
            fflush(stdout);
        }
        int tmp;
        int ans = 0;
        cin >> n >> str >> str;
        for(int i = 0;i < n;i++){
            cin >> tmp;
            ans |= (1 << (tmp - 1));
        }
        printf("%d\n",ans);
        fflush(stdout);
    }
}

C 網絡支付的回調通知系統

很繁雜的一道模擬題,用優先隊列模擬,隊友賽後強擼補完了。。晚點補。

隊友的代碼:

#include<bits/stdc++.h>
#include<time.h>
#define ll long long
using namespace std;

struct data{
    string post;
    ll getTime,sendTime;
    int fashi;
    bool operator < (const data &a) const { 
          if(sendTime != a.sendTime) return sendTime>a.sendTime;
          else  return getTime>a.getTime;
    }
}packet; 

priority_queue<data> all,que;
vector<data> ans;
map<ll,bool> stop;
char ret[105];
int plu[6] = {10,60,1800,7200,43200,86400};

ll getTime(char* str){
    struct tm stm;
    memset(&stm,0,sizeof(stm));
    ll year = 0,month = 0,day=0,hour=0,m=0,s=0;
    for(int i = 0;i < 4;i++)
        year = year * 10 + str[i] - '0';
    for(int i = 5;i < 7;i++)
        month = month * 10 + str[i] - '0';
    for(int i = 8;i < 10;i++)
        day = day * 10 + str[i] - '0';
    for(int i = 11;i < 13;i++)
        hour = hour * 10 + str[i] - '0';
    for(int i = 14;i < 16;i++)
        m = m * 10 + str[i] - '0';
    for(int i = 17;i < 19;i++)
        s = s * 10 + str[i] - '0';  
    stm.tm_year=year-1900;  
    stm.tm_mon=month-1;  
    stm.tm_mday=day;  
    stm.tm_hour=hour + 8;  
    stm.tm_min=m;  
    stm.tm_sec=s; 
    return mktime(&stm); 
}

void getNewTime(ll data){
    struct tm *p;
    time_t t = data;  
    p=gmtime(&t);  
    strftime(ret, sizeof(ret), "%Y-%m-%d %H:%M:%S", p);
}

int main(){
    int T,q;
    char str[1000000],tmp[1000000];
    scanf("%d",&T);
    while(T--){
        stop.clear();
        while(!all.empty()) all.pop();
        while(!que.empty()) que.pop();
        int n;
        scanf("%d",&n);
        getchar();
        for(int i = 0;i < n;i++){
            gets(str);
            packet.post = str;
            for(int j = 13;j < 32;j++) tmp[j - 13] = str[j];
            tmp[32] = '\0';
            packet.getTime = packet.sendTime = getTime(tmp);
            packet.fashi = 0;
            all.push(packet);
        }
        int m;
        scanf("%d",&m);
        getchar();
        for(int i = 0;i < m;i++){
            gets(str);
            stop[getTime(str)] = true;
        }
        scanf("%d",&q);
        getchar();
        while(q--){
            ans.clear();
            int len = 0;
            gets(str);
            ll now = getTime(str);
            while(!all.empty()){
                data temp = all.top();
                if(temp.sendTime > now) break;
                all.pop();
                que.push(temp);
            }
            while(!que.empty()){
                data temp = que.top();
                if(temp.sendTime >= now) break;
                que.pop();
                if(!stop[temp.sendTime]) continue;
                if(temp.fashi >= 5){
                    temp.sendTime += plu[5];
                }else{
                    temp.sendTime += plu[temp.fashi++];
                }
                que.push(temp);
            }
            while(!que.empty()){
                ans.push_back(que.top());
                que.pop();
                len++;
                if(len == 100) break;
            }
            for(int i = 0;i < len;i++){
                getNewTime(ans[i].sendTime);
                cout<<ans[i].post;
                printf(",%s\n",ret);
                que.push(ans[i]);
            }
        }
    }
}
/*
1
8
{"datetime":"2014-06-15 08:37:18","callbackurl":"abc.com"}
{"datetime":"2014-06-15 08:37:19","callbackurl":"abc.com"}
{"datetime":"2014-06-15 08:37:20","callbackurl":"ab.com"}
{"datetime":"2014-06-15 08:37:21","callbackurl":"a.com"}
{"datetime":"2014-06-15 08:37:22","callbackurl":"abc.com"}
{"datetime":"2014-06-15 08:37:23","callbackurl":"ac.com"}
{"datetime":"2014-06-15 08:37:31","callbackurl":"ac.com"}
{"datetime":"2014-06-15 08:37:33","callbackurl":"acm.com"}
4
2014-06-15 08:37:18
2014-06-15 08:37:20
2014-06-15 08:37:21
2014-06-15 08:37:28
3
2014-06-15 08:37:18
2014-06-15 08:37:20
2014-06-15 08:37:29
*/

D 第一章:異世界修仙

題目:
有n個點,如果滿足強聯通性(就是可以從i點到j點且可以從j點到i點),則他們可以算作一個羣。
現在問最少花費多少可以使所有點都給打通,羣內只要有一個點被打通了,所有點都被打通。
並求方案數。

題解:
一個很裸的Tarjan算法。。判斷強聯通之後,在強聯通的圖中,找到最小花費和最小花費的方案數,然後兩兩羣的方案數相乘,兩兩羣最小花費相加即可。

代碼:

/*
@resources: BNUZCPC D
@date: 2017-5-16
@author: QuanQqqqq
@algorithm: tarjan 
*/
#include <bits/stdc++.h>

#define MAXN 100005
#define ll long long
#define INF 0x3f3f3f
#define MOD 1000000007

using namespace std;

struct node{
    ll col,tot;
}color[MAXN];;

bool vis[MAXN];
vector<int> vs[MAXN];
int low[MAXN],dfn[MAXN];
stack<int> s;
int idx,col_num,col_t;
ll c[MAXN];

void Tarjan(int v){
    dfn[v] = low[v] = idx++;
    vis[v] = true;
    s.push(v);
    for(int i = 0;i < vs[v].size();i++){
        if(!dfn[vs[v][i]]){
            Tarjan(vs[v][i]);
            low[v] = min(low[v],low[vs[v][i]]);
        } else if(vis[vs[v][i]]) {
            low[v] = min(low[v],dfn[vs[v][i]]);
        }
    }
    if(dfn[v] == low[v]){
        vis[v] = false;
        ll maxt = c[v];
        ll tot = 0;
        while(!s.empty()){
            if(s.top() != v){
                if(maxt > c[s.top()]){
                    tot = 0;
                    maxt = c[s.top()];
                }
                if(maxt == c[s.top()]){
                    tot++;
                }
                vis[s.top()] = false;
                s.pop();
            } else {
                break;
            }
        }
        if(maxt == c[s.top()]){
            tot++;
        }
        color[col_t].col = maxt;
        color[col_t].tot = tot;
        col_t++;
        s.pop();
    }
}

void addEdge(int u,int v){
    vs[u].push_back(v);
}

void init(){
    idx = col_num = 1;
    col_t = 0;
    while(!s.empty()){
        s.pop();
    }   
    for(int i = 0;i < MAXN;i++){
        vs[i].clear();
    }
    memset(color,0,sizeof(color));
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
}

int main(){
    int T,cas = 1,n,m,v,u;
    scanf("%d",&T);
    while(T--){
        init();
        scanf("%d",&n);
        for(int i = 1;i <= n;i++){
            scanf("%lld",&c[i]);
        }
        scanf("%d",&m);
        while(m--){
            scanf("%d %d",&u,&v);
            addEdge(u,v);
        }
        for(int i = 1;i <= n;i++){
            if(!dfn[i]){
                Tarjan(i);
            }
        }
        ll ans1 = 0,ans2 = 1;
        for(int i = 0;i < col_t;i++){
            ans1 += color[i].col;
            ans2 = (ans2 * color[i].tot) % MOD;
        }
        printf("Case #%d: %lld %lld\n",cas++,ans1,ans2);
    }
}

E Enigma Pro

題目:
一個編碼器,按照題目模擬,三個轉盤,每次需要先經過配線版,再經過三個轉盤,在經過反射器,再反向經過三個轉盤,再經過配線版。。

題解:
按照題目模擬即可。只是,樣例那很容易wa,因爲,他的字母是按順序的。。。
反向的時候要特別注意,對應的是哪個字符,唯一坑點。

代碼:

/*
@resources: BNUZCPC E
@date: 2017-5-16
@author: QuanQqqqq
@algorithm: 模擬 
*/
#include <bits/stdc++.h>

#define MAXN 30

using namespace std;

char mapp[200];
char zp[10][MAXN];
char ban[200];
char fz[10][200];
char str[2005];
int m,z1,z2,z3,s1,s2,s3;

void zhuan(){
    s1++;
    if(s1 == 26){
        s1 = 0;
        s2++;
    }
    if(s2 == 26){
        s2 = 0;
        s3++;
    }
    if(s3 == 26){
        s3 = 0;
    }
}

char encode(char c){
    if(ban[c] != -1){
        c = ban[c];
    }
    c = zp[z1][(c - 'a' + s1) % 26];
    c = zp[z2][(c - 'a' + s2) % 26];
    c = zp[z3][(c - 'a' + s3) % 26];
    c = mapp[c];
    c = zp[z3][fz[z3][(fz[z3][c] - s3 + 26) % 26 + 'a']];
    c = zp[z2][fz[z2][(fz[z2][c] - s2 + 26) % 26 + 'a']];
    c = zp[z1][fz[z1][(fz[z1][c] - s1 + 26) % 26 + 'a']];
    if(ban[c] != -1){
        c = ban[c];
    }
    zhuan();
    return c;
}

int main(){
    int T,cas = 1;
    char a,b;
    scanf("%d",&T);
    getchar();
    while(T--){
        memset(mapp,0,sizeof(mapp));
        memset(zp,0,sizeof(zp));
        memset(fz,0,sizeof(fz));
        memset(ban,-1,sizeof(ban));
        for(int i = 0;i < 13;i++){
            scanf("%c %c",&a,&b);
            getchar();
            mapp[a] = b;
            mapp[b] = a;
        }
        scanf("%d",&m);
        getchar();
        for(int i = 1;i <= m;i++){
            for(int j = 0;j < 26;j++){
                scanf("%c",&zp[i][j]);
                fz[i][zp[i][j]] = j;
                getchar();
            }
        }
        scanf("%d %d %d",&z1,&z2,&z3);
        scanf("%d %d %d",&s1,&s2,&s3);
        int tmp1 = s1,tmp2 = s2,tmp3 = s3;
        scanf("%d",&m);
        getchar();
        while(m--){
            scanf("%c %c",&a,&b);
            getchar();
            ban[a] = b;
            ban[b] = a;
        }
        scanf("%d",&m);
        getchar();
        printf("Case #%d:\n",cas++);
        while(m--){
            gets(str);
            int len = strlen(str);
            for(int i = 0;i < len;i++){
                if(str[i] == ' '){
                    printf(" ");
                } else {
                    printf("%c",encode(str[i]));
                }
            }
            printf("\n");
            s1 = tmp1,s2 = tmp2,s3 = tmp3;
        }
    }
}

F 華農酸奶配方

題意:
給一個有序的數,需要找出裏面一個區間內滿足排序後連續的方案數。

題解:
orz某大牛學長留的防ak題。時間複雜度硬卡到O(n)。單調棧+並查集。
只能想到用線段樹維護O(nlogn)的算法。
每次進入一個數,維護這個線段樹該區間的最大值,最小值,區間和。
如果滿足maxn * (maxn + 1) / 2 - minn * (minn + 1) / 2 == total 且 r - l = maxn - minn就可以統計方案數。
多的不講了。。反正菜,寫不出來。

G 鳳凰山下的纜車與電瓶車

題意:
1.某號纜車或某號電瓶車單程票,耗費c1塊錢
2.不限次數的某號纜車或某號電瓶車票,耗費c2塊錢
3.不限次數的所有纜車或電瓶車票,耗費c3塊錢
4.不限次數的所有纜車和電瓶車票,耗費c4塊錢
現在知道纜車n個編號和電瓶車m個編號,和某學生乘坐交通工具的詳細情況,請你找出該學生需要花費的最小金錢。

題解:
水題。累加上來之後每一層對比就可以了。

/*
@resources: BNUZCPC G
@date: 2017-5-14
@author: QuanQqqqq
@algorithm: yy
*/
#include <bits/stdc++.h>

#define MAXN 1005

using namespace std;

int main(){
    int T,cas = 1,c1,c2,c3,c4,n,m,tmp,m1,m2;
    scanf("%d",&T);
    while(T--){
        scanf("%d %d %d %d %d %d",&c1,&c2,&c3,&c4,&n,&m);
        m1 = m2 = 0;
        for(int i = 0;i < n;i++){
            scanf("%d",&tmp);
            m1 += min(tmp * c1,c2);
        }
        for(int i = 0;i < m;i++){
            scanf("%d",&tmp);
            m2 += min(tmp * c1,c2);
        }
        printf("Case #%d: %d\n",cas++,min(c4,min(m1,c3) + min(m2,c3)));
    }
}

H 獎學金戰爭

題意:
兩個人玩遊戲,錢多的那個人(a)要給錢少的那個人(b),b擁有的錢的數量。問最終能否平分

題解:
如果,有一個人的錢爲0(且兩個不全爲0)肯定是No,如果相加是奇數肯定是No。
如果相加之後的數,除去尾0(比賽的時候死wa這裏。。最後都沒找出來)。如果是2^n,就一定是Yes。
否則,模擬一下相加的數,一直除2,看看a和b是否有在這個數裏出現過,如果出現了就是Yes。

代碼:

/*
@resources: BNUZCPC H
@date: 2017-5-14
@author: QuanQqqqq
@algorithm: yy
*/
#include <bits/stdc++.h>

#define ll long long

using namespace std;

bool check(ll n){
    while(n){
        if(n != 1 && (n & 1)){
            return false;
        }
        n >>= 1;
    }
    return true;
}

int main(){
    int T,cas = 1;
    ll n,m;
    scanf("%d",&T);
    while(T--){
        scanf("%lld %lld",&n,&m);
        printf("Case #%d: ",cas++);
        if(n == m){
            puts("Yes");
            continue;
        } else if(n == 0 || m == 0 || (n + m) % 2){
            puts("No");
            continue;
        }
        while(n % 10 == 0 && m % 10 == 0){
            n /= 10;
            m /= 10;
        }
        ll sum = n + m;
        if(check(sum)){
            puts("Yes");
            continue;
        }
        if(n > m){
            swap(n,m);
        }
        while(sum){
            if(sum == n){
                puts("Yes");
                break;
            }
            if(sum % 2){
                puts("No");
                break;
            }
            sum /= 2;
        }
    }
}

I 厲害了我的Q

題目:
小Q(菜雞)要從(0,0,0)點開始走到題目給出的各個點,途中還能向上飛向下飛(不能遁地),最終要走到(a,b,0)這個點。問方案數有多少。

題解:
其實可以分位置來考慮。
水平和豎直的其實不會影響的。(比賽時以爲會影響。。想出了一個O(n^3)妥妥的放棄了)
對於水平方向,有dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
對於豎直方向,有dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j] + dp[i - 1][j + 1]
然後最終點直接相乘即可。豎直方向的數是一個默慈金數,水平方向的明顯打表。

這裏要注意。。豎直方向如果在線算的話,時間複雜度是不夠的。因爲n個點的情況下再算上3000 * 1500 是妥妥超時的,默慈金數是可以打表的。所以兩個都離線打表就好了。豎直方向的i代表要走的步數,所以應該是3001爲最大。

代碼:

/*
@resources: BNUZCPC I
@date: 2017-5-16
@author: QuanQqqqq
@algorithm: math 
*/
#include <bits/stdc++.h>

#define MAXN 1505
#define MOD 1000000007
#define ll long long

using namespace std;

ll level[MAXN][MAXN];
ll height[MAXN * 2][MAXN];


struct point{
    ll x,y;
    point(ll _x,ll _y) : x(_x),y(_y){}
    point(){}
}; 

point a[MAXN],tmp;

ll myAbs(ll a){
    return a > 0 ? a : -a;
}

void init(){
    level[1][1] = height[1][1] = 1;
    for(ll i = 1;i < MAXN;i++){
        for(ll j = 1;j < MAXN;j++){
            if(i == 1 && j == 1){
                continue;
            }
            if(i >= 2){
                level[i][j] += level[i - 1][j];
            }
            if(j >= 2){
                level[i][j] += level[i][j - 1];
            }
            level[i][j] %= MOD; 
        }
    }
    for(ll i = 2;i < MAXN * 2;i++){
        for(ll j = 1;j <= i && j < MAXN - 1;j++){
            height[i][j] = (height[i - 1][j - 1] + height[i - 1][j] + height[i - 1][j + 1]) % MOD;
        }
    }
}

ll getLen(point a,point b){
    return myAbs(a.x - b.x) + myAbs(a.y - b.y);
}

int main(){
    init();
    ll T,n,cas = 1;
    scanf("%lld",&T);
    while(T--){
        scanf("%lld",&n);
        ll ans = 1;
        a[0] = point(0,0);
        for(ll i = 1;i <= n;i++){
            scanf("%lld %lld",&a[i].x,&a[i].y);
            tmp = point(myAbs(a[i].x - a[i - 1].x) + 1,myAbs(a[i].y - a[i - 1].y) + 1);
            ans = (ans * ((height[getLen(a[i],a[i - 1]) + 1][1] * level[tmp.x][tmp.y]) % MOD)) % MOD;
        }
        printf("Case #%lld: %lld\n",cas++,ans);
    }
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章