The 3rd Universal Cup. Stage 23: Hong Kong

Preface

去年的香港站,本来两个礼拜没摸键盘了,但意外打的很顺,最后出了 7 个题感觉都能干进捧杯区了,只能感慨摆烂使人进步啊


B. Defeat the Enemies

考虑 DP,令 \(f_{i,j}\) 表示一共造成了 \(i\) 点伤害,且被护甲稀释的伤害最多为 \(j\) 所需的最小代价,方案数顺便一起维护

由于被护甲稀释的伤害 \(<k\),因此第二维是 \(O(k)\) 的,DP 转移时只需要枚举下一击的伤害量,总复杂度 \(O(mk^2)\)

实现时有部分边界需要特别注意

#include <bits/stdc++.h>

#define int int64_t

constexpr int mod = 998244353;

void chmax(int &a, int b) {
    if(b > a) a = b;
}

void chmin(int &a, int b) {
    if(b < a) a = b;
}

void add(int &a, int b) {
    if((a += b) >= mod) a -= mod;
}

void work() {
    int n, m; std::cin >> n >> m;
    std::vector<int> a(n), b(n);
    for(auto &a: a) std::cin >> a;
    for(auto &b: b) std::cin >> b;

    int k; std::cin >> k;
    std::vector<int> c(k + 1);
    for(int i = 1; i <= k; ++i) std::cin >> c[i];

    std::vector<std::array<int, 101>> prep(m + 1);
    for(int i = 0; i <= m; ++i) for(int j = 0; j <= 100; ++j)
        prep[i][j] = 0;

    for(int i = 0; i < n; ++i)
        for(int j = 1; j <= k; ++j)
            chmax(prep[b[i] - 1][j], a[i] + b[i] + j - 1);

    for(int j = 1; j < k; ++j)
        for(int i = m; i >= 1; --i)
            chmax(prep[i - 1][j + 1], prep[i][j]);

    int hkr = 0;
    for(int i = 0; i < n; ++i) chmax(hkr, a[i] + b[i]);
    const int U = 2 * m + 2 * k + 100;
    std::vector<std::array<int, 100>>
        dp1(U + 1),
        dp2(U + 1);

    for(int i = 0; i <= U; ++i) for(int j = 0; j < 100; ++j)
        dp1[i][j] = 0x3fffffffffffffffLL, dp2[i][j] = 0;
    
    dp1[0][0] = 0;
    dp2[0][0] = 1;

    int ans = 0x3fffffffffffffffLL, ans_count = 0;
    for(int i = 0; i <= U; ++i) for(int j = 0; j < k; ++j) {
        if(i >= hkr + j) {
            if(dp1[i][j] < ans) ans = dp1[i][j], ans_count = dp2[i][j]; else
            if(dp1[i][j] == ans) add(ans_count, dp2[i][j]);
        }
        for(int x = 1; x <= k && i + x <= U; ++x) {
            int ncost = dp1[i][j] + c[x];
            int ni = i + x;
            int nj = j;
            if(i <= m) chmax(nj, prep[i][x] - hkr);
            if(ncost < dp1[ni][nj]) {
                dp1[ni][nj] = ncost;
                dp2[ni][nj] = dp2[i][j];
            } else
            if(ncost == dp1[ni][nj]) {
                add(dp2[ni][nj], dp2[i][j]);
            }
        }
    }

    std::cout << ans << ' ' << ans_count << char(10);
    return ;
}

int32_t main() {
    std::ios::sync_with_stdio(false);

    int T; std::cin >> T; while(T--) work();
    return 0;
}

C. The Story of Emperor Bie

签到,首先不难发现答案只可能是最大值所在的位置

手玩一下会发现其实从这些位置的任意一个开始推都是等价的,而题目又保证一定有解,因此输出这些位置即可

#include<cstdio>
#include<iostream>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
const int N=500005;
int t,n,a[N];
int main()
{
    for (scanf("%d",&t);t;--t)
    {
        scanf("%d",&n);
        for (RI i=1;i<=n;++i) scanf("%d",&a[i]);
        int mx=*max_element(a+1,a+n+1);
        for (RI i=1;i<=n;++i) if (a[i]==mx) printf("%d ",i);
        putchar('\n');
    }
    return 0;
}

E. Concave Hull

挺难的一个几何题,祁神赛时+赛后调了挺久才过的,我连题目都没看就不做评论了

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

const int N = 2005;
const int MOD = (int)1e9+7;

void inc(int &x, int a) {if ((x+=a)>=MOD) x-=MOD;}
void dec(int &x, int a) {if ((x-=a)<0) x+=MOD;}

struct Pt {
    int x, y;
    Pt operator-(const Pt &b) const {return Pt{x-b.x, y-b.y};}
    Pt operator+(const Pt &b) const {return Pt{x+b.x, y+b.y};}
    bool operator<(const Pt &b) const {return x!=b.x ? x<b.x : y<b.y;}
    int crs(const Pt &b) const {return x*b.y-y*b.x;}
    int quad() const {
        if (x>0 && y>=0) {return 1;} if (x<=0 && y>0) {return 2;}
        if (x<0 && y<=0) {return 3;} if (x>=0 && y<0) {return 4;}
        return 0;
    }
};

struct arcPt {
    Pt v;
    int qd, id;
    bool operator< (const arcPt b) const {
        if (qd != b.qd) return qd < b.qd;
        else return v.crs(b.v) > 0;
    }
};

#define ft first
#define sd second

int n, ans, areaConvh;
int stk[N]; int tp=-1;
Pt pt[N];
bool onConvh[N];
vector<arcPt> arc[N];

vector<int> makeConvh(vector<int> &vec) {
    sort(vec.begin(), vec.end(), [&](int a, int b) {return pt[a] < pt[b];});
    int sz = vec.size();
    vector<int> res(sz+5);
    int top = -1;
    res[++top] = vec[0];
    for (int i=1; i<sz; ++i) {
        while (top > 0 && (pt[res[top]]-pt[res[top-1]]).crs(pt[vec[i]]-pt[res[top]]) <= 0) --top;
        res[++top] = vec[i];
    }
    int mx = top;
    for (int i=sz-2; i>=0; --i) {
        while (top > mx && (pt[res[top]]-pt[res[top-1]]).crs(pt[vec[i]]-pt[res[top]]) <= 0) --top;
        res[++top] = vec[i];
    }
    res.erase(res.begin()+top, res.end());
    return res;
}

int getConvhArea(vector<int> convh) {
    int res = 0;
    int sz = convh.size();
    for (int i=0; i<sz; ++i) {
        res += (pt[convh[i]].crs(pt[convh[(i+1)%sz]])) % MOD;
    }
    return res;
}

int cross(int p, int a, int b) {return abs((pt[a]-pt[p]).crs(pt[b]-pt[p]))%MOD ;}

// int getPlace(int center, int after, int x, int sel) {
//     Pt v = pt[x] - pt[center];
//     int qd = v.quad();
//     int res1 = lower_bound(arc[center].begin(), arc[center].end(), arcPt{v, qd, x}) - arc[center].begin(); 
//     int res2 = lower_bound(arc[center].begin(), arc[center].end(), arcPt{v, qd+4, x}) - arc[center].begin(); 
//     if (1==sel) return res1 >= after ? res1 : res2;
//     return res2 <= after ? res2 : res1;
// }

signed main() {
    ios::sync_with_stdio(0); cin.tie(0);
    cin >> n;
    for (int i=0; i<n; ++i) {
        cin >> pt[i].x >> pt[i].y;
    }

    vector<int> idd(n);
    for (int i=0; i<n; ++i) idd[i] = i;
    vector<int> convh = makeConvh(idd);
    for (int x : convh) onConvh[x] = true;
    areaConvh = getConvhArea(convh);
    // printf("areaConvh : %lld\n", areaConvh);
    
    for (int i=0; i<n; ++i) {
        for (int j=0; j<n; ++j) if (j!=i) {
            Pt v = pt[j]-pt[i];
            int qd = v.quad();
            arc[i].push_back({v, qd, j});
            arc[i].push_back({v, qd+4, j});
        }
        sort(arc[i].begin(), arc[i].end());
    }
    // for (int i=0; i<n; ++i) {
    //     printf("arc[%lld]:", i);
    //     for (auto [v, qd, x] : arc[i]) printf(" %lld", x);
    //     puts("");
    // }

    for (int i=0; i<n; ++i) if (!onConvh[i]) {
        int L = 0;
        while (!onConvh[arc[i][L].id]) ++L;
        int bg = arc[i][L].id; 
        int cnt = 0;
        // int rcnt = 0;
        // int rarea = 0;
        for (int j=L+1; j<arc[i].size(); ++j) {
            ++cnt;
            if (!onConvh[arc[i][j].id]) continue;
            // printf("i=%lld j=%lld crs=%lld\n", i, j, cross(i, arc[i][L].id, arc[i][j].id));
            // rarea += cross(i, arc[i][L].id, arc[i][j].id);
            ans = (ans + (areaConvh - cross(i, arc[i][L].id, arc[i][j].id) + MOD)%MOD * cnt % MOD)%MOD;
            // rcnt += cnt;
            cnt = 0;
            L = j;
            if (arc[i][L].id == bg) break;
        }
        // printf("rcnt = %lld\n", rcnt);
        // printf("rarea = %lld\n", rarea);
    }

    for (int i=0; i<n; ++i) if (!onConvh[i]) {
        int L = 0;
        while (!onConvh[arc[i][L].id]) ++L;
        int bg = arc[i][L].id; 
        tp = -1; stk[++tp] = arc[i][L].id;
        int sum = (pt[i].crs(pt[arc[i][L].id]) %MOD + MOD)%MOD;

        // printf("333333\n");
        // vector<int> dbg = vector<int>({i, arc[i][L].id});
        for (int j=L+1; j<arc[i].size(); ++j) {
            if (onConvh[arc[i][j].id]) {
                if (bg == arc[i][j].id) break;
                L = j;
                tp = -1; stk[++tp] = arc[i][L].id;
                sum = (pt[i].crs(pt[arc[i][L].id]) %MOD + MOD)%MOD;
                // printf("i=%lld L=%lld id[L]=%lld sum=%lld\n", i, L, arc[i][L].id, sum);
                // printf("2222\n");
                // dbg = vector<int>({i, arc[i][L].id});
                continue;
            }
            // printf("i=%lld, j=%lld sum=%lld\n", i, j, sum);
            while (tp>0 && (pt[stk[tp]]-pt[stk[tp-1]]).crs(pt[arc[i][j].id]-pt[stk[tp-1]]) <= 0) {
                sum = (sum - (pt[stk[tp-1]].crs(pt[stk[tp]])%MOD) + MOD)%MOD;
                // printf("11111\n");
                --tp;
            }
            // dbg.push_back(arc[i][j].id);
            // printf("tp=%lld id[j]=%lld sum=%lld\n", stk[tp].ft, arc[i][j].id, sum);
            stk[++tp] = arc[i][j].id;
            sum = (sum + (pt[stk[tp-1]].crs(pt[stk[tp]])%MOD) + MOD)%MOD;
            ans = (ans + (sum + pt[stk[tp]].crs(pt[i])%MOD + MOD)%MOD)%MOD;
            // printf("dbg:"); for (int x : dbg) printf(" %lld", x); puts("");
            // auto dbgconvh = makeConvh(dbg); printf("dbgconvh:"); for (int x : dbgconvh) printf(" %lld", x); puts("");
            // printf("sum=%lld convh=%lld\n", sum, sum + pt[stk[tp].ft].crs(pt[i]));
            // printf("i=%lld j=%lld id[j]=%lld L=%lld id[L]=%lld convh=%lld convh_ans=%lld\n", i, j, arc[i][j].id, L, arc[i][L].id, (sum + pt[stk[tp]].crs(pt[i])), getConvhArea(makeConvh(dbg)));
            // assert((sum + pt[stk[tp]].crs(pt[i])) == getConvhArea(makeConvh(dbg)));
        }
    }
    
    // printf("44444\n");
    for (int i=0; i<n; ++i) if (!onConvh[i]) {
        int L = arc[i].size() - 1;
        while (!onConvh[arc[i][L].id]) --L;
        int bg = arc[i][L].id;
        tp = -1; stk[++tp] = arc[i][L].id;
        int sum = (pt[arc[i][L].id].crs(pt[i]) %MOD + MOD)%MOD;
        
        for (int j=L-1; j>=0; --j) {
            if (onConvh[arc[i][j].id]) {
                if (bg == arc[i][j].id) break;
                L = j;
                tp = -1; stk[++tp] = arc[i][L].id;
                sum = (pt[arc[i][L].id].crs(pt[i])%MOD + MOD)%MOD;
                continue;
            }
            
            while (tp>0 && (pt[arc[i][j].id]-pt[stk[tp-1]]).crs(pt[stk[tp]]-pt[stk[tp-1]]) <= 0) {
                sum = (sum - pt[stk[tp]].crs(pt[stk[tp-1]])%MOD + MOD)%MOD;
                --tp;
            }
            stk[++tp] = arc[i][j].id;
            sum = (sum + pt[stk[tp]].crs(pt[stk[tp-1]])%MOD + MOD) % MOD;
            ans = (ans + (sum + pt[i].crs(pt[stk[tp]])%MOD + MOD)%MOD ) % MOD;
            // printf("i=%lld j=%lld id[j]=%lld L=%lld id[L]=%lld convh=%lld\n", i, j, arc[i][j].id, L, arc[i][L].id, (sum + pt[i].crs(pt[stk[tp]])));
        }
    }

    cout << ans << '\n';

    return 0;
}

F. Money Game 2

感觉很显然的一个题,不知道为啥过的人不算很多

首先观察到对于位置 \(i\),其实就等价于在其左边找 \(x\) 个数,右边找 \(y\) 个数,然后按照顺序传递过来,找到满足 \(x+y<n\) 且最优的方案

一个直观的想法是求出 \(L(i,j)\) 表示位置 \(i\) 左边找了 \(j\) 个数带来的贡献,右侧同理,这样复杂度显然有点爆炸

但仔细思考会发现对于 \(L(i,\cdot)\),本质不同的值只有 \(O(\log a_i)\) 种,且值相同的保留 \(j\) 最小的即可

同时 \(L(i+1,\cdot)\) 的值可以由 \(L(i,\cdot)\) 递推而来,而 \(L(1,\cdot)\) 的值只需要暴力二分找到分界点即可,总复杂度 \(O(n\log a_i)\)

#include<cstdio>
#include<iostream>
#include<vector>
#define int long long
#define RI register int
#define CI const int&
#define fi first
#define se second
using namespace std;
typedef pair <int,int> pi;
const int N=500005;
int t,n,a[N]; vector <pi> L[N],R[N];
inline int calcL(CI k)
{
    int ret=0; for (RI i=n-k+1;i<=n;++i) ret+=a[i],ret/=2;
    return ret;
}
inline int calcR(CI k)
{
    int ret=0; for (RI i=k;i>=1;--i) ret+=a[i],ret/=2;
    return ret;
}
signed main()
{
    for (scanf("%lld",&t);t;--t)
    {
        scanf("%lld",&n);
        for (RI i=1;i<=n;++i) scanf("%lld",&a[i]);
        L[1].push_back(pi(0,0)); int tar=calcL(n-1);
        while (L[1].back().se!=tar)
        {
            int l=L[1].back().fi+1,r=n-1,mid,ret=-1;
            while (l<=r)
            {
                int mid=l+r>>1;
                if (calcL(mid)!=L[1].back().se) ret=mid,r=mid-1; else l=mid+1;
            }
            L[1].push_back(pi(ret,calcL(ret)));
        }
        for (RI i=2;i<=n;++i)
        {
            L[i].push_back(pi(0,0));
            for (auto [num,val]:L[i-1])
            {
                int nval=(val+a[i-1])/2;
                if (num+1<=n-1&&nval!=L[i].back().se)
                L[i].push_back(pi(num+1,nval));
            }
        }
        R[n].push_back(pi(0,0)); tar=calcR(n-1);
        while (R[n].back().se!=tar)
        {
            int l=R[n].back().fi+1,r=n-1,mid,ret=-1;
            while (l<=r)
            {
                int mid=l+r>>1;
                if (calcR(mid)!=R[n].back().se) ret=mid,r=mid-1; else l=mid+1;
            }
            R[n].push_back(pi(ret,calcR(ret)));
        }
        for (RI i=n-1;i>=1;--i)
        {
            R[i].push_back(pi(0,0));
            for (auto [num,val]:R[i+1])
            {
                int nval=(val+a[i+1])/2;
                if (num+1<=n-1&&nval!=R[i].back().se)
                R[i].push_back(pi(num+1,nval));
            }
        }
        for (RI i=1;i<=n;++i)
        {
            int k=R[i].size()-1,ret=0;
            for (RI j=0;j<L[i].size();++j)
            {
                while (k>=0&&L[i][j].fi+R[i][k].fi>n-1) --k;
                if (k>=0) ret=max(ret,L[i][j].se+R[i][k].se);
            }
            printf("%lld%c",ret+a[i]," \n"[i==n]);
        }
        for (RI i=1;i<=n;++i) L[i].clear(),R[i].clear();
    }
    return 0;
}

G. Yelkrab

题都没看,被徐神秒了

#include <bits/stdc++.h>

using u64 = uint64_t;

std::vector<int> hkr[1000006];

struct node_t {
    int out[26];
    int64_t count;
} node[1000006];

void work() {
    int n; std::cin >> n;
    u64 ans = 0;
    size_t sum_of_pig = 0;
    std::vector<std::string> pig(n);
    for(auto &pig: pig) std::cin >> pig, sum_of_pig += pig.size();

    std::vector<u64> ap(sum_of_pig + 1, 0);
    int O = 0;
    memset(node + O, 0, sizeof(node_t));

    int i = 0;
    for(auto &&pig: pig) {
        int cur = 0;
        for(auto c: pig) {
            int u = c - 'a';
            if(!node[cur].out[u]) {
                O += 1;
                memset(node + O, 0, sizeof(node_t));
                node[cur].out[u] = O;
            }
            cur = node[cur].out[u];
            int cc = ++node[cur].count;
            for(auto hkr: hkr[cc]) {
                ans ^= ap[hkr];
                ap[hkr] += hkr;
                ans ^= ap[hkr];
            }
        }
        std::cout << ans << char(++i == n ? 10 : 32);
    }
}

int main() {
    for(int i = 1; i <= 1000000; ++i) for(int j = i; j <= 1000000; j += i)
        hkr[j].emplace_back(i);

    int T; std::cin >> T; while(T--) work();
    return 0;
}

H. Mah-jong

首先考虑怎么快速判断一个牌的数量向量 \((c_1,c_2,\dots,c_8)\) 是否可以胡牌,其中 \(c_i\) 表示值为 \(i\) 的牌的数量

不难想到只要枚举所有可能的吃的数量,剩下的只要满足所有牌剩余数量为 \(3\) 的倍数即可

而一种吃的数量只有 \(0,1,2\) 种,因此大力枚举的复杂度为 \(3^6\),可以接受

统计时维护前缀的牌的数量向量,但直接用模意义下相减的方法会出现问题,即区间内可能没有足够的牌用来构建吃

因此还需要顺带维护出合法的左端点能到达的最大值,在这个地方统计答案即可

#include<cstdio>
#include<iostream>
#include<vector>
#include<array>
#define RI register int
#define CI const int&
using namespace std;
typedef array <int,8> st;
const int N=100005,S=6561;
int t,pw3[10],n,a[N],bkt[S];
vector <st> chows; vector <int> mdy[N];
inline void DFS(CI p,st& cur)
{
    if (p==6) return (void)(chows.push_back(cur));
    for (RI i=0;i<3;++i)
    {
        for (RI j=0;j<3;++j) cur[p+j]+=i;
        DFS(p+1,cur);
        for (RI j=0;j<3;++j) cur[p+j]-=i;
    }
}
int main()
{
    pw3[0]=1; for (RI i=1;i<8;++i) pw3[i]=pw3[i-1]*3;
    st tmp; for (RI i=0;i<8;++i) tmp[i]=0; DFS(0,tmp);
    // printf("size of chows = %d\n",(int)chows.size());
    for (scanf("%d",&t);t;--t)
    {
        scanf("%d",&n); vector <int> rollback;
        for (RI i=1;i<=n;++i) scanf("%d",&a[i]),--a[i];
        auto trs=[&](const st& tmp)
        {
            int mask=0;
            for (RI i=0;i<8;++i) mask+=tmp[i]%3*pw3[i];
            return mask;  
        };
        st pfx; for (RI i=0;i<8;++i) pfx[i]=0;
        vector <int> num[10];
        for (RI i=1;i<=n;++i)
        {
            ++pfx[a[i]]; num[a[i]].push_back(i);
            for (auto cur:chows)
            {
                bool flag=1;
                for (RI j=0;j<8;++j)
                if (pfx[j]<cur[j]) { flag=0; break; }
                if (!flag) continue;
                int pos=i; for (RI j=0;j<8;++j)
                if (cur[j]) pos=min(pos,num[j][(int)num[j].size()-cur[j]]);
                int mask=0; for (RI j=0;j<8;++j)
                mask+=(pfx[j]%3-cur[j]%3+3)%3*pw3[j];
                // printf("i = %d, mask = %d\n",i,mask);
                mdy[pos-1].push_back(mask);
            }
        }
        for (RI i=0;i<8;++i) pfx[i]=0;
        int mask=trs(pfx); ++bkt[mask]; rollback.push_back(mask);
        long long ans=0;
        for (RI i=1;i<=n;++i)
        {
            for (auto mask:mdy[i-1]) ans+=bkt[mask];
            ++pfx[a[i]];
            int mask=trs(pfx); ++bkt[mask]; rollback.push_back(mask);
        }
        printf("%lld\n",ans);
        for (auto x:rollback) bkt[x]=0;
        for (RI i=0;i<=n;++i) mdy[i].clear();
    }
    return 0;
}

K. LR String

徐神开场写的,应该是个签

#include <bits/stdc++.h>

void work() {
    std::string original; std::cin >> original;
    std::vector<std::pair<char, int>> ori;
    bool oL = (original.front() == 'L'),
         oR = (original.back()  == 'R');
    original = original.substr(oL, original.size() - oL - oR);
    for(int l = 0, r = 0; l < original.size(); l = r) {
        while(r < original.size() && original[l] == original[r])
            r++;
        ori.emplace_back(original[l], r - l);
    }
    
    int T; std::cin >> T; while(T--) {
        std::string s; std::cin >> s;
        if(oL && s.front() != 'L') {
            std::cout << "NO\n";
            continue;
        }
        if(oR && s.back()  != 'R') {
            std::cout << "NO\n";
            continue;
        }
        s = s.substr(oL, s.size() - oL - oR);
        int i = 0, p1 = 0, p2 = 0;
        while(i < s.size() && p1 < ori.size()) {
            if(p2 == ori[p1].second || s[i] != ori[p1].first) {
                p1++; p2 = 0;
            } else {
                i++; p2++;
            }
        }
        std::cout << (i == s.size() ? "YES\n" : "NO\n");
    }
    return ;
}

int main() {
    std::ios::sync_with_stdio(false);

    int T; std::cin >> T; while(T--) work();
    return 0;
}

L. Flipping Paths

首先枚举最终的目标颜色,考虑使用以下贪心策略

对于一条路径,从第一行出发,每次尽量延申到这一行最右边的不对应颜色再向下拐,直到到达最后一行时再一直向右

不难发现这种方法一次会清除一条对角线上的所有不合法颜色,由于对角线数量为 \(n+m-1\),因此可以通过

#include<cstdio>
#include<iostream>
#include<string>
#include<vector>
#define RI register int
#define CI const int&
using namespace std;
const int N=205;
int t,n,m,a[N][N]; char s[N][N];
inline bool solve(const char& tar)
{
    for (RI i=1;i<=n;++i) for (RI j=1;j<=m;++j) 
    a[i][j]=(s[i][j]==tar?0:1);
    vector <string> res;
    while ((int)res.size()<=400)
    {
        bool all_zero=1;
        for (RI i=1;i<=n;++i) for (RI j=1;j<=m;++j)
        if (a[i][j]) { all_zero=0; break; }
        if (all_zero) break;
        string way=""; int y=1;
        for (RI x=1;x<=n;++x)
        {
            int rgt=-1;
            for (RI j=m;j>=1;--j)
            if (a[x][j]) { rgt=j; break; }
            if (x==n) rgt=m;
            while (y<rgt)
            {
                a[x][y]^=1;
                way.push_back('R'); ++y;
            }
            a[x][y]^=1;
            if (x!=n) way.push_back('D');
        }
        res.push_back(way);
    }
    if ((int)res.size()<=400)
    {
        puts("YES");
        printf("%d\n",(int)res.size());
        for (auto way:res) cout<<way<<endl;
        return true;
    }
    return false;
}
int main()
{
    for (scanf("%d",&t);t;--t)
    {
        scanf("%d%d",&n,&m);
        for (RI i=1;i<=n;++i) scanf("%s",s[i]+1);
        if (solve('W')) continue;
        if (solve('B')) continue;
        puts("NO");
    }
    return 0;
}

Postscript

由于要准备组会的汇报,剩下看着可做的 J 就懒得补了,开摆就是爽啊

posted @ 2025-03-16 17:18  空気力学の詩  阅读(244)  评论(1)    收藏  举报