20220809杭电第七场

Black Magic

题目大意:
给定n个方块,每个方块左右都可能是黑色或者白色,具体如下
E:左右两边都是白***r>L:左边是黑色,右边是白***r>R:右边是白色左边是黑***r>B:左右两边都是黑***r>给定每种方块的数量
如果相邻的两个方块邻面颜色都是黑色,那么这两个方块就可以合并
求出经过处理之后最少的方块数和最大的方块数

input:
3
1 1 1 1
1 2 3 4
3 4 5 6

output:
2 4
4 8
8 16

解:
对于连通块最多的情况,我们需要让合并的方块尽可能的少
可以把L全放在最左边,R全放在最右边,然后E和B相间摆放
对于连通块最少的情况
可以先把B全合并起来,一个L和一个R也能分为一组拼起来,注意,如果有B并且有一组L和R的话,可以把一组L和R拼在B的两边,这样可以再减少一组。

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

int p,q,i,j;

ll solve2(int a,int b,int c,int d) {
    ll ans = 0;
    /*int aa=0,dd=0;
    int minn = min(c,b);
    aa = min(minn,a);
    b -= aa, c -= aa;
    minn = min(c,b);
//    dd= min(minn,d) ;
//    cout<<"dd is "<<dd<<endl;
//    b -= dd,c -=dd;
    int l = min(b,c);
    ans += 2*l;
    ans += 2*(aa+dd);
    /*if(b!=c) {
        aa += min(b,c);
        b -= min(b,c);
        c -= min(b,c);
        ans += max(b,c) - 1;
        a++;
        if(d>a) ans--;
    } 
    //if(b==c) ans+=b*2;

    ans += min(a,d)*2;
    if(a>d) ans+=a-d;
    if(d>a && a!=0) ans+=1; 
    */
    ans += c + b ;
    if(d>a) ans+=2*a+1;
    else ans += a+d; 
//    cout<<a<<" "<<b<<" "<<c<<" "<<d<<" "<<endl;
//    cout<<aa<<" "<<dd<<" "<<endl;
    return ans;
}
ll solve1(int a,int b,int c,int d) {
    swap(a,d);
    ll ans = 0; 
    if(a>0) a=1;
    if(b>0 || c>0) a=0;
    ans += d + a + max(b,c);
    return ans;
}
void solve() {
    cin>>p>>q>>i>>j;
    cout<<solve1(p,q,i,j)<<" "<<solve2(p,q,i,j)<<endl;
}

int main () {
    ios::sync_with_stdio(false) ,cin.tie(0);    
    int t;
    cin>>t; 
    while(t--) {
        solve();
    }
} 

Triangle Game

题目大意:
给定三个正整数abc代表三角形的三条边,两个人玩游戏,每回合需要挑选一条边并且让这条边减去>=1的值,如果在某个回合操作结束后三条边不能构成三角形,则游戏结束,问先手的人是否有必胜的策略

input:
3
2 2 3
2 3 4
5 3 4

output:
Win
Lose
Win

解:
结论:当(a-1)^(b-1)^(c-1)!=0时先手必胜
图片说明

#include<bits/stdc++.h>

using namespace std;


int main() {

    int t, a, b, c;
    cin >> t;
    while (t--) {
        cin >> a >> b >> c;
        if (((a - 1) ^ (b - 1) ^ (c - 1)) != 0) {
            cout << "Win" << endl;
        } else {
            cout << "Lose" << endl;
        }
    }
}

Count Stickmen

题目大意:
给你一颗树,问你树上有多少个火柴人,如下所示
图片说明
如图所示
以3,5这条骨架枚举
我们应该从一个火柴人的3,5两个部位下手
先看5下面的7和8,这是火柴人的两条腿,这是比较好求的,就是从5的所有边中减去连向3的那条边并且从剩下的边里面挑两条,用组合数计算
在看与3相连的两条手臂4,5以及9,10,这也比较好求,就是枚举3的所有邻点,将所有邻点的边数相加,最后减去3的边数,得到的结果就是与3点距离为2的点的个数,可以看图理解。但是这中点不能和5相连,因为和5相连的会是腿,所以要减去(5的边数-1)。在这些点里面选出两个点,用组合数求解。
但是如果两条手臂相同,即选到了像腿一样的两条手臂,我们必须减去这种情况,这种情况方案数就是从3的邻点中除了腿去枚举,将枚举的点的边数减一,得到的就是每个点下面有多少边,从这些边中选出两条来,最后将结果累加就是多余的情况。
选择头的话方案数明显是3的边数-3(身体和两只手臂)。


#include<bits/stdc++.h>

using namespace std;
#define int long long

vector<int> v[500005];
int edges[500005];//每个点有多少条边
int help1[500005];//du-dx
int help2[500005];//两个手臂相同的方案数
const int mod = 998244353;

int n, temp1, temp2;


int add(int a, int b) {
    return (a += b) >= mod ? a - mod : a;
}

int sub(int a, int b) {
    return (a -= b) < 0 ? a + mod : a;
}


int C(int x) {
    return x * (x - 1) / 2 % mod;
}

void solve() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        v[i].clear();
        help1[i] = 0;
        help2[i] = 0;
        edges[i] = 0;
    }
    for (int i = 1; i <= n - 1; i++) {
        cin >> temp1 >> temp2;
        v[temp1].push_back(temp2);
        v[temp2].push_back(temp1);
        edges[temp1]++;
        edges[temp2]++;
    }
    for (int i = 1; i <= n; i++) {
        for (auto &y: v[i]) {
            help1[i] = add(help1[i], edges[y] - 1);
            help2[i] = add(help2[i], C(edges[y] - 1));
        }
//        help2[i] = sub(help2[i], C(edges[i] - 1));
    }
    int ans = 0;
    int legs, hands, head;
    for (int i = 1; i <= n; i++) {
        if (edges[i] >= 4) {//对类似样例中点3这样的点枚举,只有边数大于等于四才有可能成为点三那样的点
            for (auto &j: v[i]) {//枚举这个点所有的邻点
                if (edges[j] >= 3) {//先找到腿的节点
                    head = sub(edges[i], 3);
                    legs = sub(edges[j], 1);
                    hands = sub(help1[i], legs);
                    legs = C(legs);
                    hands = sub(C(hands), sub(help2[i], C(edges[j] - 1)));
                    ans = add(ans, head * hands % mod * legs % mod);
                }
            }
        }
    }
    cout << ans << endl;

}


signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
}
#ACM##菜鸡的求救#
全部评论

相关推荐

10-17 16:07
门头沟学院 Java
牛牛大你18号:在汇报,突然弹出来,,领导以为我在准备跳槽,刚从领导办公室谈心出来
点赞 评论 收藏
分享
双非坐过牢:非佬,可以啊10.28笔试,11.06评估11.11,11.12两面,11.19oc➕offer
点赞 评论 收藏
分享
评论
1
收藏
分享
牛客网
牛客企业服务