2024牛客暑期多校第二场

目录

A-Floor Tiles

B-MST

G-The Set of Squares

I-Red Playing Cards


A-Floor Tiles

发现答案对于一个大小为 N × M 的平面,其曲线总数为 N + M+ 平面结构

内部环的数目
最小值必然可以没有环,可以使用全 A 或者全 B 的方式很容易构造。
最大值用类似   AB 的方式  可推出左上角为AB时的最大曲线数。最小都是N+M。
                         BA
构造就根据给定的一块,然后贪心得把左上的求出来,然后根据需要的曲线数量删环
#include <bits/stdc++.h>
using namespace std;
const int N = 810;

int n, m, k;
int g[N][N];

void solve()
{
    cin >> n >> m >> k;
    int u, v, op;
    string s;
    cin >> u >> v >> s;
    op = s[0] - 'A';

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            if((i + j) % 2 == (u + v) % 2)
                g[i][j] = op;
            else g[i][j] = op ^ 1;

    int cnt = g[1][1] == 0 ? n + m + ((n - 1) * (m - 1) + 1) / 2 : n + m + (n - 1) * (m - 1) / 2;
    if(k > cnt || k < n + m)
    {
        cout << "No" << '\n';
        return;
    }

    op ^= 1;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            if(cnt > k)
            {
                if(op == 0 && g[i][j] == 0)
                {
                    if(i + 1 <= n && j + 1 <= m)
                        g[i][j] ^= 1, cnt --;
                }   
                if(op == 1 && g[i][j] == 1)
                {
                    if(i + 1 <= n && j - 1 >= 1)
                        g[i][j] ^= 1, cnt --;
                }
            }

    cout << "Yes" << '\n';
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
            cout << (char)('A' + g[i][j]);
        cout << '\n';
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int T = 1;
    cin >> T;
    while(T --)
        solve();

    return 0;
}

B-MST

因为总的点数只有1e5

对于询问集合中点多的,直接用克鲁斯卡尔每次的复杂度是O(m)

对于询问集合中点不多的,可以用prim算法,也可以把这些点有关的边都取出来跑克鲁斯卡尔

取出有关的边的方式

#include<bits/stdc++.h>

//#define int long long
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
//#define int ll
const int N = 1e6 + 100;
const ll mod = 998244353;

int vis[N];
struct node {
    int u, v, w;
} a[N];

bool cmp(node xx, node yy) {
    return xx.w < yy.w;
}

vector<pair<int,int> >e[N];

int f[N];

int find(int x) {
    if (f[x] == x)return x;
    else return f[x] = find(f[x]);
}

void merge(int x, int y) {
    f[find(x)] = find(y);
}


void solve() {
    int n, m, q;
    cin >> n >> m >> q;
    for (int i = 1; i <= m; i++) {
        long long u, v, w;
        cin >> u >> v >> w;
        a[i].u = u;
        a[i].v = v;
        a[i].w = w;
        e[u].push_back({v,w});
        e[v].push_back({u,w});
    }
    for(int i=1;i<=n;i++){
        sort(e[i].begin(),e[i].end());
    }
    sort(a + 1, a + m + 1, cmp);
    for(int ii=1;ii<=q;ii++){
        int sz;
        ll ans = 0;
        cin >> sz;
        if (sz == 1) {
            int x;
            cin>>x;
            cout << 0 << '\n';
        } else if (sz >= 900) {
            for (int i = 1; i <= sz; i++) {
                int x;
                cin >> x;
                vis[x] = ii;
                f[x] = x;
            }
            int cntt=0;
            for (int i = 1; i <= m; i++) {
                int u = a[i].u;
                int v = a[i].v;
                int w = a[i].w;
                if (vis[u] !=ii || vis[v] != ii)continue;
                int x = find(u);
                int y = find(v);
                if (x == y)continue;
                ans += w;
                cntt++;
                merge(x, y);
            }
            if (cntt==sz-1) {
                cout << ans << '\n';
            } else {
                cout << -1 << '\n';
            }
        } else {
            vector<int> v(sz+10);
            for(int i=0;i<sz;i++){
                cin>>v[i];
                f[v[i]]=v[i];
            }
            vector<array<int,3> > edge;
            for(int i=0;i<sz;i++){
                for(int j=i+1;j<sz;j++){
                    int x=v[i],y=v[j];

                    if(y>e[x].back().first)continue;

                    int l=-1,r=e[x].size()-1;
                    while(l+1<r){
                        int mid=l+r>>1;
                        if(e[x][mid].first>=y)r=mid;
                        else l=mid;
                    }

                    if(e[x][r].first==y){
                        edge.push_back({e[x][r].second,x,y});
                    }
                }
            }
            sort(edge.begin(),edge.end());
            for(array<int,3> it:edge){
                int fx=find(it[1]),fy=find(it[2]);
                if(fx!=fy){
                    sz--;
                    ans+=it[0];
                    merge(fx,fy);
                }
            }
            if(sz==1)
                cout<<ans<<'\n';
            else cout<<-1<<'\n';
        }
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int _ = 1;
//    cin >> _;
    while (_--) solve();
    return 0;
}

prim的方式

#include<bits/stdc++.h>

#define int long long
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
//#define int ll
const int N = 1e5 + 100;
const ll mod = 998244353;

int vis[N];
unordered_map<int, int> p[N];
struct node {
    int u, v, w;
} a[N];

bool cmp(node xx, node yy) {
    return xx.w < yy.w;
}

int f[N];

int find(int x) {
    if (f[x] == x)return x;
    else return f[x] = find(f[x]);
}

void merge(int x, int y) {
    f[find(x)] = find(y);
}


void solve() {
    int n, m, q;
    cin >> n >> m >> q;
    for (int i = 1; i <= m; i++) {
        long long u, v, w;
        cin >> u >> v >> w;
        a[i].u = u;
        a[i].v = v;
        a[i].w = w;
        p[u][v]=w;
        p[v][u]=w;
    }
    sort(a + 1, a + m + 1, cmp);
    for(int ii=1;ii<=q;ii++){
        int sz;
        ll ans = 0;
        cin >> sz;
        if (sz == 1) {
            int x;
            cin>>x;

            cout << 0 << '\n';
        } else if (sz >= sqrt(N)) {
            for (int i = 1; i <= sz; i++) {
                int x;
                cin >> x;
                vis[x] = ii;
                f[x] = x;
            }
            int cntt=0;
            for (int i = 1; i <= m; i++) {
                int u = a[i].u;
                int v = a[i].v;
                int w = a[i].w;
                if (vis[u] !=ii || vis[v] != ii)continue;
                int x = find(u);
                int y = find(v);
                if (x == y)continue;
                ans += w;
                cntt++;
                merge(x, y);
            }
            if (cntt==sz-1) {
                cout << ans << '\n';
            } else {
                cout << -1 << '\n';
            }
        } else {


            vector<ll> ve, d(sz + 1, 1e15);
            vector<int>vis2(sz + 1, 0);

            for (int i = 1; i <= sz; i++) {
                int x;
                cin >> x;
                f[x] = x;
                ve.push_back(x);
            }
            for (int i = 0; i < sz; i++) {
                for (int j = 0; j < sz; j++) {
                    if (i == j)continue;
                    if (p[ve[i]].count(ve[j])) {
                        merge(ve[i], ve[j]);
                    }
                }
            }
            int kk = -1;
            int ff = 1;
            for (int i = 0; i < sz; i++) {
                if (kk == -1)kk = find(ve[i]);
                else if (kk != find(ve[i])) {
                    ff = 0;
                }
            }
            if (ff == 0) {
                cout << -1 << '\n';
                continue;
            }
            for (int i = 1; i < sz; i++) {
                if (!p[ve[0]].count(ve[i]))continue;
                long long dis = p[ve[0]][ve[i]];
                d[i] = dis;
            }

            long long mi = 1e15, idx = -1;
            vis2[0] = 1;

            for (int i = 0; i < sz - 1; i++) {
                mi = 1e15,idx = -1;
                for (int j = 0; j < sz; j++) {
                    if (vis2[j] == 0 && d[j] < mi) {
                        mi = d[j];
                        idx = j;
                    }
                }
                vis2[idx] = 1;
                ans += d[idx];
                for (int k = 0; k < sz; k++) {
                    if (vis2[k] ==0 && p[ve[idx]].count(ve[k]) && p[ve[idx]][ve[k]] < d[k]) {
                        d[k] = min(d[k], p[ve[idx]][ve[k]]);
                    }
                }
            }
            cout << ans << '\n';
        }
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int _ = 1;
//    cin >> _;
    while (_--) solve();
    return 0;
}

G-The Set of Squares

对于000以内的数,质因子中不可能出现两个大于 32 的质数,所以根据大因子进行分组,因为好集的概念是平方,所以只需要判断每个质因子出现的次数是奇数次还是偶数次,用二进制的概念用01表示出现偶数和奇数,根据大质数进行不同的状压dp,

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define int long long
#define endl '\n'

vector<int> p = { 2,3,5,7,11,13,17,19,23,29,31 };
const int MOD = 1e9 + 7;

void Prework() {

}
void Solve() {
    int n;cin >> n;
    map<int, vector<array<int, 2>>> mp;
    for (int i = 1;i <= n;i++) {
        int x;cin >> x;
        int mask = 0;
        int val = 1;
        for (int j = 0;j < p.size();j++) {
            while (x % p[j] == 0) {
                x /= p[j];
                mask ^= 1 << j;
                if (~mask >> j & 1) val = val * p[j];
            }
        }
        mp[x].push_back({ mask,val });
    }
    int u = (1 << 12) - 1;
    vector<int> dp(u + 1);dp[0] = 1;
    for (auto [x, v] : mp) {
        for (auto [mask, val] : v) {
            auto ndp = dp;
            if (x!= 1) mask |= 1 << 11;
            for (int i = 0;i <= u;i++) {
                int ni = i ^ mask;
                int mult = val;
                for (int j = 0;j < 11;j++) {
                    if ((mask >> j & 1) && (i >> j & 1)) mult = mult * p[j] % MOD;
                }
                if ((i >> 11 & 1) && (mask >> 11 & 1)) mult = mult *x  % MOD;
                (ndp[ni] += mult * dp[i] % MOD) %= MOD;
            }
            swap(ndp, dp);
        }
        for (int i = 1 << 11;i <= u;i++) {
            dp[i] = 0;
        }
    }
    cout << (dp[0] - 1 + MOD) % MOD << endl;


}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T = 1;
    //cin >> T;
    Prework();
    while (T--) Solve();
}



I-Red Playing Cards

被包含的两个连续段之间,里面的如果先取的话,可能会使外侧的区间的长度减少,所以可以按照长度排序,然后记下来每一种区间如果取走的最优贡献,在算长区间时可以直接用这个已经存下来的值去优化dp。

#include <bits/stdc++.h>
using namespace std;
const int N=6e3+7;
int n,a[N];
int l[N],r[N],w[N],dp[N],ans[N];
bool cmp(int a,int b){
    return r[a]-l[a]<r[b]-l[b];
}
int upd(int x,int y,int c){
    memset(dp,0,sizeof(dp));
    for(int i=x;i<=y;i++){
        if(l[a[i]]==i)
            dp[r[a[i]]]=max(dp[r[a[i]]],ans[a[i]]+dp[l[a[i]]-1]);
        dp[i]=max(dp[i],dp[i-1]+c);
    }
    return dp[y];
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    for(int i=1;i<=n*2;i++) cin>>a[i],r[a[i]]=i;
    for(int i=2*n;i>=1;i--) l[a[i]]=i;
    for(int i=1;i<=n;i++) w[i]=i;
    sort(w+1,w+n+1,cmp);
    for(int i=1;i<=n;i++) ans[w[i]]=upd(l[w[i]],r[w[i]],w[i]);
    cout<<upd(1,2*n,0)<<'\n';
    return 0;
}

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心刍

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值