2023年中国大学生程序设计竞赛女生专场

Dashboard - 2023年中国大学生程序设计竞赛女生专场 - Codeforces

K. RSP

诈骗题 / 签到题。本来用排列组合算期望发现这个平局很奇妙,好像期望最大的就是m-1个平局,一局决定胜负。

void solve() {
    int n,m; cin>>n>>m;
    cout<<"1/"<<n<<endl;
}

A. 疾羽的救赎

模拟 + 栈,根据题意进行模拟,注意移动时要把它上面的一起进行移动。写的复杂了

void solve() {
    vector<vector<int>> ph(12);
    ph[2].push_back(1); ph[3].push_back(2); ph[4].push_back(3);
    vector<int> pos({0,2,3,4});
    for(int i = 0; i < 12; ++i) {
        int a,b; cin>>a>>b;
        int ed = pos[a] + b;
        int st = pos[a];
        vector<int> tmp;
        while(ph[st].size() && ph[st].back() != a) {
            tmp.push_back(ph[st].back());
            ph[st].pop_back();
        }
        if(ph[st].size() && ph[st].back() == a) {
            tmp.push_back(ph[st].back());
            ph[st].pop_back();
        }
        for(int j = tmp.size() - 1; j >= 0; --j) ph[ed].push_back(tmp[j]);
        for(auto &t: ph[ed]) pos[t] = ed;
    }
    puts(ph[9].size() == 3 ? "Y" : "N");
}

L. 养成游戏

n,m,k很小,爆搜重复太多会TLE,优化一下就可以过了,大概是排列搜索典题。

给属性分配任意的属性点,在满足属性点小于等于K的情况下进行计算评分。

void solve() {
    int n,m,k; cin>>n>>m>>k;
    vector<array<int,7>> ask(m);
    for(auto &t: ask) {
        cin>>t[0]>>t[1]>>t[2]>>t[3]>>t[4]>>t[5]>>t[6];
    }
    vector<int> val(n + 1);
    int ans = -1e18;
    auto dfs = [&](auto &&self, int last, int from) -> void {
        int mi = 0;
        // 计算评分
        for(auto &t: ask) {
            int ai = val[t[0]], aj = val[t[1]];
            int a = t[3], b = t[4], d = t[5], v = t[6];
            if(t[2] == 1) {
                if(ai * a + b * aj >= d) mi += v;
            } else {
                if(ai * a + b * aj <= d) mi += v;
            }
        }
        ans = max(ans, mi);
        if(last <= 0) return ;
        for(int i = from; i <= n; ++i) {
            if(val[i] >= k) continue;
            last--;
            val[i]++;
            self(self, last, i);
            last++;
            val[i]--;
        }
    };
    dfs(dfs,k * n, 1);
    cout<<ans<<endl;
}

G. 精灵宝可梦对战

模拟 + 队列。主要是模拟,但是需要注意不同于我们一般认知的是:打完就换下一个

例如,Apg先打,打完Apg跑到后面。到Bpg攻击时,攻击的是队列中的下一个,而不是那个攻击Bpg的PG。

之后就是模拟,使用技能攻击高的,如果有多个攻击高的,优先使用非终极技能。

我是这样模拟的:Apg先攻击Bpg,之后A攻击完后换其他的Apg。如果Bpg还有Hp就攻击那个新的Apg,否则Bpg换后面的攻击Apg。最后如果Bpg还有Hp放入队列后面;如果Apg还有Hp放到队列前面

void solve() {
    int n,m,k; cin>>n>>m>>k;
    vector<array<int,8>> A(n),B(m);
    deque<array<int,8>> Aq, Bq; // Hi, Ai, Bi, Ci, Di, Ei, Wi 
    for(auto &t: A) {
        cin>>t[0]>>t[1]>>t[2]>>t[3]>>t[4]>>t[5]>>t[6];
        Aq.push_back(t);
    }
    for(auto &t: B) {
        cin>>t[0]>>t[1]>>t[2]>>t[3]>>t[4]>>t[5]>>t[6];
        Bq.push_back(t);
    }
    for(int i = 0; i < k; ++i) {
        auto Apg = Aq.front(), Bpg = Bq.front(); Aq.pop_front(); Bq.pop_front();
        // Apgo对Bpgo的伤害
        int phy = max(0LL, Apg[1] - Bpg[3]);
        int mgc = max(0LL, Apg[2] - Bpg[4]);
        int real = 0;
        if(Apg[7] >= Apg[5]) real = Apg[6];
        int ma = max(phy, mgc);
        if(ma >= real) {
            // 魔法 / 物理
            Bpg[0] -= ma;
            Apg[7]++;
        } else {
            Bpg[0] -= real;
            Apg[7] -= Apg[5];
        }

        Aq.push_back(Apg);
        Apg = Aq.front(); Aq.pop_front();

        if(Bpg[0] > 0) {
            phy = max(0LL, Bpg[1] - Apg[3]);
            mgc = max(0LL, Bpg[2] - Apg[4]);
            real = 0;
            if(Bpg[7] >= Bpg[5]) real = Bpg[6];
            ma = max(phy, mgc);
            if(ma >= real) {
                Apg[0] -= ma;
                Bpg[7] ++;
            } else {
                Apg[0] -= real;
                Bpg[7] -= Bpg[5];
            }
        } else {
            // Bpg = 
            if(Bq.size() == 0) {
                cout<<"Alice";
                return;
            }
            Bpg = Bq.front(); Bq.pop_front();

           phy = max(0LL, Bpg[1] - Apg[3]);
            mgc = max(0LL, Bpg[2] - Apg[4]);
            real = 0;
            if(Bpg[7] >= Bpg[5]) real = Bpg[6];
            ma = max(phy, mgc);
            if(ma >= real) {
                Apg[0] -= ma;
                Bpg[7] ++;
            } else {
                Apg[0] -= real;
                Bpg[7] -= Bpg[5];
            }
        }
        if(Bpg[0] > 0) Bq.push_back(Bpg);
        if(Apg[0] > 0) Aq.push_front(Apg);
        if(Bq.size() == 0) {
            cout<<"Alice";
            return ;
        }
        if(Aq.size() == 0) {
            cout<<"Bob";
            return ;
        }
    }
    cout<<"Draw";
}

F. 最长上升子序列

构造。首先想到:后面比前面最多大1。

很像之前做过的拓扑序题,找一个满足条件的一个序列。但是对于用拓扑只有一点思路,没有找到切入点。

不过最长上升子序列。后面比前面的大,一定用到了前面的贡献,1 2 3 ... m形如这样的可以用递增来填充。但是多个这个填充在给定条件中如果成立,则所有形如那样的序列分配都是合理的。

根据样例和自己造的数据发现:相同值对应元素按逆序填充是满足条件的。

in:
5
1 2 2 3 3
out: # 逆序
1 3 2 5 4

in:
4
1 2 1 2
out: # 逆序
2 4 1 3
void solve() {
    int n; cin>>n;
    vector<int> a(n + 1);
    map<int,vector<int>> mp; 
    for(int i = 1; i <= n; ++i) cin>>a[i], mp[a[i]].push_back(i);
    int ma = 0;
    for(int i = 1; i <= n; ++i) {
        if(a[i] > ma + 1) {
            puts("-1");
            return ;
        }
        ma = max(ma, a[i]);
    }
    vector<int> pos(n + 1);
    int now = 1;
    for(auto &t: mp) {
        auto vec = t.vs;
        for(int i = vec.size() - 1; i >= 0; --i) pos[vec[i]] = now++;
    }
    for(int i = 1; i <= n; ++i) cout<<pos[i]<<" ";
}

你可能感兴趣的:(cf,算法题,算法,数据结构)