20180922北京网络赛题解

20180922北京网络赛题解

A.Saving Tang Monk II

MEANING

\(n \times m\)的网格图,可以向四个方向移动,移动一格耗时1秒,毒气室额外花费1秒,S表示起点,T表示终点,#表示毒气室,拥有氧气瓶才能进入,且消耗一个氧气瓶,每次进入B获得一个氧气瓶,最多同时携带5瓶氧气瓶,进入P获得一个加速,使消耗的时间减少1秒。.表示空的房间。问从S到T最少耗时。

SOLUTION

优先队列BFS,耗时少的点优先。vis[x][y][k]表示在(x,y)有k个氧气瓶,每个状态只访问一次。

CODE

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 105;
const int dirx[] = {1,-1,0,0};
const int diry[] = {0,0,1,-1};
char mapp[MAXN][MAXN];
bool vis[MAXN][MAXN][6];
int n,m;
struct node{
    int x,y,step,oxg;
};
bool operator<(node a,node b){
    return a.step>b.step;
}
int bfs(node st,node et){
    priority_queue<node> q;
    memset(vis,0,sizeof vis);
    q.push(st);
    vis[st.x][st.y][st.oxg] = 1;
    while(q.size()){
        node cur = q.top();
        if(cur.x==et.x&&cur.y==et.y)return cur.step;
        q.pop();
        for(int i=0;i<4;i++){
            int xx = cur.x+dirx[i],yy = cur.y+diry[i],oo = cur.oxg,ss = cur.step;
            if(xx<0||xx>=n||yy<0||yy>=m)continue;
            if(oo==0&&mapp[xx][yy]=='#')continue;
            if(mapp[xx][yy]=='#')oo--,ss++;
            if(mapp[xx][yy]=='B')oo = min(oo+1,5);
            if(vis[xx][yy][oo])continue;
            vis[xx][yy][oo] = 1;
            if(mapp[xx][yy]=='P')q.push({xx,yy,ss,oo});
            else q.push({xx,yy,ss+1,oo});
        }
    }
    return -1;
}

int main() {
    while(scanf("%d%d",&n,&m)&&n){
        for(int i=0;i<n;i++){
            scanf("%s",mapp[i]);
        }
        node st,et;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(mapp[i][j]=='S'){
                    st={i,j,0,0};
                }
                if(mapp[i][j]=='T'){
                    et={i,j,0,0};
                }
            }
        }
        cout<<bfs(st,et)<<endl;
    }
    return 0;
}

B.Tomb Raider

MEANING

n个字符串,每个字符串是个环,可以自己选起点,输出字典序最小的LCS。

CODE

数据很小,暴力
队友代码

#include <stdio.h>
#include <time.h>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <set>

using namespace std;
typedef long long ll;
const int maxn = 2000005;

struct SSAM {
    int next[50][26];
    int len;
    set<int>cp[26];
    int find(int p,int ch){
        set<int>::iterator  it = cp[ch].upper_bound(p);
        if (it==cp[ch].end()) return -1;
        else return *it;
    }
    void build(char s[]){
        for (int i=0;i<26;i++) cp[i].clear();
        len = strlen(s);
        for (int i=0;i<len;i++){
            cp[s[i]-'a'].insert(i+1);
            cp[s[i]-'a'].insert(i+len+1);
        }
        for (int i=0;i<=2*len;i++){
            for (int j=0;j<26;j++){
                next[i][j] = find(i,j);
            }
        }
    }
    bool check(char s[]){
        int le = strlen(s);
        for (int i=0;i<len;i++){
            int j = i;
            for (int k=0; k<le;k++ ) {
                j = next[j][s[k]-'a'];
                if ( j==-1 || j> i+len ) break;
               // printf("j=%d\n",j);
            }
            if ( j!=-1 && j <= i+len) return true;
        }
        return false;
    }
    void show(){
        for (int i=0;i<=2*len;i++){
            for (int j=0;j<26;j++){
                printf("%d ",next[i][j]);
            }printf("\n");
        }
        printf("\n");
    }
}ssam[20];
ll n;
char str[50][20];

char tmp[50];

string  solve(){
    int len = strlen(str[1]);
    string ans = "";
    for (int i=1;i<=(1<<len)-1;i++){
        int k=0;
        for (int j=0;j<len;j++) {
            if (i & (1 << j)) tmp[k++] = str[1][j];
        }
        tmp[k]='\0';
        for (int qwe=0;qwe<k;qwe++) {
            int ff = 1;
            for (int l = 2; l <= n; l++) {
                if (!ssam[l].check(tmp)) {
                    ff = 0;
                    break;
                }
            }
            if (ff == 1) {
                string tt = tmp;
                if (tt.length() > ans.length()) {
                    ans = tt;
                } else if (tt.length() == ans.length()) {
                    if (tt < ans) {
                        ans = tt;
                    }
                }
            }
            char rty = tmp[0];
            for (int asd=1;asd<k;asd++) tmp[asd-1] = tmp[asd];
            tmp[k-1] = rty;
        }
    }
    return ans;
}

int main() {
    while (scanf("%lld", &n) != EOF) {
        for (int i = 1; i <= n; i++) {
            scanf("%s", str[i]);
            ssam[i].build(str[i]);
        }
        string ans = solve();
        if (ans == "") {
            printf("0\n");
        } else {
            printf("%s\n", ans.c_str());
        }
    }
    return 0;
}

C.Cheat

MEANING

四个人打一副牌,先出完所有牌的player获胜。游戏的规则是,四个人按顺时针轮流出牌,每次出牌时将牌反置,并声明自己所出的牌均为某一点数(RANK)。其余三人依次决定是否质疑。如果选择质疑,翻开牌,如果与声明一致,质疑者将牌桌所有牌收回手中,反之出牌者将所有牌收回手中。如果没人质疑,牌将留在桌上。每个人声明的RANK从A开始,后一人声明的RANK必须且只能比前一人声明的大一级,特别的,K之后为A,如此循环。
这四个人每个都有自己的出牌策略和质疑策略。
player1:出牌策略:如果拥有当前必须声明的RANK,打出一张。否则不得不lie,将一张手中RANK的字典序最小的牌打出,并声明为当前RANK。质疑策略:当自己是下一个出牌者,且不得不lie时,质疑之。或者当前出牌者声明的RANK有p张牌,自己手中有q张时,且p+q>4,质疑之。
player2:出牌策略:如果拥有当前必须声明的RANK,打出该RANK的全部牌,否则不得不lie,将一张手中RANK的字典序最小的牌打出,并声明为当前RANK。质疑策略:当且仅当自己是下一个出牌者,且不得不lie时,质疑之。
player3:出牌策略:如果拥有当前必须声明的RANK,打出该RANK的全部牌,否则不得不lie,打出数量最小的某一RANK的全部牌,如果有多种,打出RANK的字典序最小的,并声明为当前RANK。质疑策略:当且仅当自己拥有出牌者所声明的RANK的全部4张牌时,质疑之。
player4:出牌策略:如果拥有当前必须声明的RANK且有3张或者4张时,打出该RANK的全部牌。否则除了打出该RANK的全部牌(如果有的话),额外加上一张RANK的字典序最小的牌(如果有的话)。质疑策略:当且仅当出牌者没有手牌时,质疑之。

SOLUTION

按题意模拟。
有两个坑。
一是牌的RANK字典序和RANK不一样,容易忽略J<K<Q。
二是player4需要出的牌少于三张时,而又无其它RANK的牌时,此时说的是真话。

CODE

#include<bits/stdc++.h>
using namespace std;

int Rank[] = {9, 1, 2, 3, 4, 5, 6, 7, 8, 0, 10, 12, 11}; //rank

int hand[5][14];//lex
int tran(char s[]) { // char[] to number
    if(strcmp(s, "A") == 0)return 9;
    if(strcmp(s, "J") == 0)return 10;
    if(strcmp(s, "Q") == 0)return 12;
    if(strcmp(s, "K") == 0)return 11;
    if(strcmp(s, "10") == 0)return 0;
    return s[0] - '0' - 1;
}
void NeTran(int num,char s[]){
    if(num==9)strcpy(s,"A");
    else if(num==10)strcpy(s,"J");
    else if(num==12)strcpy(s,"Q");
    else if(num==11)strcpy(s,"K");
    else if(num==0)strcpy(s,"10");
    else{
        s[0] = num+1+'0';
        s[1] = '\0';
    }
}

bool check(int player) {
    for(int i = 0; i < 13; i++)if(hand[player][i])return false;
    return true;
}

int cnt;
int roundHolder, requireRank;
int cardNum;
bool state;
int realcard[15];

void putDown(int player) {
    memset(realcard,0,sizeof realcard);
    cardNum = 0;
    if(player == 1) {
        if(hand[player][requireRank]) {
            hand[player][requireRank]--;
            realcard[requireRank]++;
            cardNum = 1;
            state = 1;
        } else {
            for(int i = 0; i < 13; i++) {
                if(hand[player][i]) {
                    hand[player][i]--;
                    realcard[i]++;
                    cardNum = 1;
                    break;
                }
            }
            state = 0;
        }
    }
    else if(player == 2) {
        if(hand[player][requireRank]) {
            realcard[requireRank] = hand[player][requireRank];
            cardNum = hand[player][requireRank];
            hand[player][requireRank] = 0;
            state = 1;
        } else {
            for(int i = 0; i < 13; i++) {
                if(hand[player][i]) {
                    hand[player][i]--;
                    realcard[i]++;
                    cardNum = 1;
                    break;
                }
            }
            state = 0;
        }
    }
    else if(player == 3) {
        if(hand[player][requireRank]) {
            realcard[requireRank] = hand[player][requireRank];
            cardNum = hand[player][requireRank];
            hand[player][requireRank] = 0;
            state = 1;
        } else {
            int tot = -1;
            for(int i = 0; i < 13; i++) {
                if(hand[player][i] && (tot==-1||hand[player][i]<hand[player][tot]))tot = i;
            }
            realcard[tot] = hand[player][tot];
            cardNum = hand[player][tot];
            hand[player][tot] = 0;
            state = 0;
        }
    }
    else  {
        if(hand[player][requireRank] == 3 || hand[player][requireRank] == 4) {
            realcard[requireRank] = hand[player][requireRank];
            cardNum = hand[player][requireRank];
            hand[player][requireRank] = 0;
            state = 1;
        } else {
            realcard[requireRank] = hand[player][requireRank];
            cardNum = hand[player][requireRank];
            hand[player][requireRank] = 0;
            state = 1;
            for(int i = 0; i < 13; i++) {
                if(hand[player][i]) {
                    hand[player][i]--;
                    realcard[i]++;
                    cardNum++;
                    state = 0;
                    break;
                }
            }
        }
    }
}

int nextRequireRank() {
    return Rank[(cnt + 1) % 13];
}

bool willChallenge(int player) {
    if(player == 1) {
        if(roundHolder == 4 && hand[player][nextRequireRank()]==0)
            return true;
        for(int i = 0; i < 13; i++) {
            if(hand[player][requireRank] + cardNum > 4)return true;
        }
        return false;
    }
    else if(player == 2) {
        if(roundHolder == 1 && hand[player][nextRequireRank()]==0)
            return true;
        return false;
    }
    else if(player == 3) {
        if(hand[player][requireRank] == 4)return true;
        return false;
    }
    else{
        if(check(roundHolder))return true;
        return false;
    }
}

bool challenge() {
    return !state;
}

int table[15];
void takesBack(int player) {
    for(int i = 0; i < 13; i++) {
        hand[player][i] += table[i];
        table[i] = 0;
    }
}

void init() {
    memset(table,0,sizeof table);
    memset(hand,0,sizeof hand);
    memset(realcard,0,sizeof realcard);
}

int main() {
//    IN_PC();
    char card[5];
    while(scanf("%s", card) != EOF) {
        init();
        hand[1][tran(card)]++;
        for(int i = 0; i < 12; i++) {
            scanf("%s", card);
            hand[1][tran(card)]++;
        }
        for(int i = 2; i <= 4; i++) {
            for(int j = 0; j < 13; j++) {
                scanf("%s", card);
                hand[i][tran(card)]++;
            }
        }
        cnt = 0;
        roundHolder = 1, requireRank = Rank[cnt % 13];
        int winner = 0;
        while(1) {
            putDown(roundHolder);
            for(int i = 0; i < 13; i++) {
                table[i] += realcard[i];
            }
            for(int i = 1; i <= 3; i++) {
                int challenger = (roundHolder % 4 + i-1)%4+1;
                if(willChallenge(challenger)) {
                    if(challenge())
                        takesBack(roundHolder);
                    else
                        takesBack(challenger);
                }
            }
            if(check(roundHolder)) {
                winner = roundHolder;
                break;
            }
            cnt++;
            requireRank = Rank[cnt % 13];
            roundHolder = roundHolder % 4 + 1;
        }
        for(int i = 1; i <= 4; i++) {
            if(winner==i){
                printf("WINNER\n");
            }
            else{
                int flag = 0;
                for(int j=0;j<13;j++){
                    for(int k=0;k<hand[i][Rank[j]];k++){
                        char ans[5];
                        NeTran(Rank[j],ans);
                        if(flag==0){
                            flag = 1;
                        }
                        else printf(" ");
                        printf("%s",ans);
                    }
                }
                puts("");
            }
        }
    }
    return 0;
}

D.80 Days

CODE

队友代码

#include <stdio.h>
#include <time.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2000005;

ll val[maxn<<2];

ll sum[maxn];

void build(ll rt,ll l,ll r){
    if (l==r){
        val[rt] = sum[l];
    } else {
        ll mid = (l+r)/2;
        build(rt<<1,l,mid);
        build(rt<<1|1,mid+1,r);
        val[rt] = min(val[rt<<1],val[rt<<1|1]);
    }
}

ll query(ll rt,ll l,ll r,ll L,ll R){
    if (L<=l&&r<=R){
        return val[rt];
    } else {
        ll mid = (l+r)/2;
        ll ret = 1e18;
        if (L<=mid) ret = min(ret,query(rt<<1,l,mid,L,R));
        if (mid<R) ret =min(ret,query(rt<<1|1,mid+1,r,L,R));
        return  ret;
    }
}
int main() {
    ll t;
    scanf("%lld",&t);
    while (t--){
        ll n,c;
        scanf("%lld%lld",&n,&c);
        for (int i=1;i<=n;i++) {
            scanf("%lld",&sum[i]);
        }
        for (int i=1;i<=n;i++) {
            ll tmp;
            scanf("%lld",&tmp);
            sum[i]-=tmp;
            sum[n+i]=sum[i];
        }
        for (ll i=1;i<=2*n;i++){
            sum[i]=sum[i-1]+sum[i];
        }
        build(1,1,2*n);
        ll ans = -1;
        for (int i=1;i<=n;i++){
            if ( (sum[i]-sum[i-1]+c>=0)&&  query(1,1,2*n,i,n+i-1) + c >= sum[i-1] ){
                ans = i;
                break;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2018-09-22 22:41  NeilThang  阅读(207)  评论(0编辑  收藏  举报