2025.4.19 Neowise Labs Contest 1 (Codeforces Round 1018, Div. 1 + Div. 2)
A. Wonderful Sticks
题意:给一个大于号和小于号的序列,构造一个排列,要求:如果第 \(i\) 个字符是大于号则第 \(i+1\) 个数比前面所有的字符都大;如果第 \(i\) 个字符是小于号则第 \(i+1\) 个数比前面所有的字符都小。
从后往前构造,如果是大于号则取目前剩余的最大数,小于号则取目前剩余的最小数。
void solve(){
    int n; cin >> n;
    string s; cin >> s;
    vector <int> ans(n);
    int l=1, r=n;
    for (int i=n-1; i>0; --i)
    {
        if (s[i-1] == '<') ans[i] = l++;
        else ans[i] = r--;
    }
    ans[0] = l;
    for (int i=0; i<n; ++i) cout << ans[i] << ' ';
    cout << '\n';
}
B. Wonderful Gloves
题意:有 \(n\) 种手套,第 \(i\) 种有 \(l_i\) 个左手套和 \(r_i\) 个右手套。问至少取多少只手套可以保证取到至少 \(k\) 双不同种类的手套。
最坏情况下,所有手套都取走 \(\max\{l_i,r_i\}\) 只,且其中 \(k-1\) 种被全部取走,另一种被取走一双。
void solve(){
    int n, k; cin >> n >> k;
    vector <pii> a(n);
    for (int i=0; i<n; ++i) cin >> a[i].first;
    for (int i=0; i<n; ++i) cin >> a[i].second;
    for (int i=0; i<n; ++i)
    {
        if (a[i].first > a[i].second) swap(a[i].first, a[i].second);
    }
    ll ans = 0;
    for (int i=0; i<n; ++i) ans += a[i].second;
    sort (all(a));
    for (int i=n-1; i>n-k; --i) ans += a[i].first;
    ans ++;
    cout << ans << '\n';
}
C. Wonderful City
题意:给一个矩阵,你可以以 \(a_i\) 的代价给第 \(i\) 行元素整体加 \(1\)(每行仅限一次),也可以以 \(b_i\) 的代价给第 \(i\) 列元素整体加 \(1\)(每列仅限一次)。进行若干次操作使得矩阵相邻元素不同,求最小代价。
行列是独立的。考虑对行和列分别做 dp。设 \(f_{i,0/1}\) 表示第 \(i\) 行不加/加的最小代价,则转移依赖于第 \(i\) 行和第 \(i+1\) 行之间是否有对应的相等、少1、多1的元素。
int n, a[N][N], b[N], c[N];
ll f[N][2], ans;
void solve(){
    cin >> n;
    for (int i=1; i<=n; ++i)
        for (int j=1; j<=n; ++j)
            cin >> a[i][j];
    for (int i=1; i<=n; ++i) cin >> b[i];
    for (int i=1; i<=n; ++i) cin >> c[i];
    for (int i=1; i<=n; ++i) f[i][0] = f[i][1] = INF;
    f[1][0] = 0, f[1][1] = b[1];
    for (int i=1; i<n; ++i)
    {
        bool fl1 = 0, fl2 = 0, fl3 = 0;
        for (int j=1; j<=n; ++j)
        {
            if (a[i][j] == a[i+1][j]) fl1 = 1;
            if (a[i][j] == a[i+1][j]+1) fl2 = 1;
            if (a[i][j] == a[i+1][j]-1) fl3 = 1;
        }
        if (fl1 && fl2 && fl3)
        {
            cout << "-1\n";
            return;
        }
        if (!fl1) f[i+1][0] = min(f[i+1][0], f[i][0]);
        if (!fl3) f[i+1][0] = min(f[i+1][0], f[i][1]);
        if (!fl2) f[i+1][1] = min(f[i+1][1], f[i][0] + b[i+1]);
        if (!fl1) f[i+1][1] = min(f[i+1][1], f[i][1] + b[i+1]);
    }
    ans = min(f[n][0], f[n][1]);
    
    for (int i=1; i<=n; ++i) f[i][0] = f[i][1] = INF;
    f[1][0] = 0, f[1][1] = c[1];
    for (int i=1; i<n; ++i)
    {
        bool fl1 = 0, fl2 = 0, fl3 = 0;
        for (int j=1; j<=n; ++j)
        {
            if (a[j][i] == a[j][i+1]) fl1 = 1;
            if (a[j][i] == a[j][i+1]+1) fl2 = 1;
            if (a[j][i] == a[j][i+1]-1) fl3 = 1;
        }
        if (fl1 && fl2 && fl3)
        {
            cout << "-1\n";
            return;
        }
        if (!fl1) f[i+1][0] = min(f[i+1][0], f[i][0]);
        if (!fl3) f[i+1][0] = min(f[i+1][0], f[i][1]);
        if (!fl2) f[i+1][1] = min(f[i+1][1], f[i][0] + c[i+1]);
        if (!fl1) f[i+1][1] = min(f[i+1][1], f[i][1] + c[i+1]);
    }
    ans += min(f[n][0], f[n][1]);
    if (ans > 1e15) cout << -1 << '\n';
    else cout << ans << '\n';
}
D. Wonderful Lightbulbs
题意:有一个无穷大的 01 矩阵,初始只有一个值为 1 其他都为 0。现进行若干次操作,每次选择一个位置 \((x,y)\) 将 \((x,y),(x+1,y),(x,y+1),(x+1,y-1)\) 的值都反转。给出操作结束后的矩阵,求最开始 1 的位置。
首先作变换 \((x,y)\mapsto (x,x+y)\),则操作变成给 \((x,y),(x+1,y),(x,y+1),(x+1,y+1)\) 反转。
设变换后 1 的位置的横坐标集合为 \(X\) 纵坐标集合为 \(Y\),则操作对横纵坐标是独立的且不会改变 \(\oplus X\) 和 \(\oplus Y\) 的值。因此全 xor 起来即可。
void solve(){
    int n, x, y;
    cin >> n;
    ll X = 0, Y = 0;
    for (int i=1; i<=n; ++i)
    {
        cin >> x >> y;
        X ^= x, Y ^= y+x; 
    }
    cout << X << ' ' << Y-X << '\n';
}

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号