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);
    }
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章