2021牛客暑期多校训练营3

C.Minimum grid

题意

有一个 n×n 网格,它的一些位置包含非负整数 a i , j a_{i,j} ai,j ,而其他位置不包含任何内容。同时给出每行的max,每列的max,向网格里填数,使得数的总和最小

思路

每行每列,是不是给人一种二分图的感觉?
对于每一个max,先都加进去,在m行的输入中检查是否有行最大,等于列最大的,有则连边。
然后对每一行跑一遍二分图,找到最大,使得减去的max的和最大

代码

/*
 * @Author: Icey_dying
 * @Date: 2021-07-24 15:14:48
 * @LastEditors: Icey_dying
 * @LastEditTime: 2021-07-29 15:23:58
 * @FilePath: \Icey_dying\competition\2021.07.24\C.cpp
 */
#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int N=4e6+5;
struct node{
    int ver,next;
}e[N];
int tot,head[N];
int b[N],v[N],c[N];
int ans,n,m,k;
int match[N];
void add(int x,int y)
{
    e[++tot].ver=y;
    e[tot].next=head[x];
    head[x]=tot;
}
bool dfs(int x)
{
    for(int i=head[x];i;i=e[i].next){
        int y=e[i].ver;
        if(v[y]) continue;
        v[y]=1;
        if(!match[y]||dfs(match[y])){
            match[y]=x;
            return 1;
        }
    }
    return 0;
}
int main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++) scanf("%d",&b[i]),ans+=b[i];
    for(int i=1;i<=n;i++) scanf("%d",&c[i]),ans+=c[i];
    for(int i=1;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        if(b[x]==c[y]) add(x,y);
    }
    for(int i=1;i<=n;i++){
        memset(v,0,sizeof(v));
        if(dfs(i)) ans-=b[i];
    }
    cout<<ans<<endl;
    return 0;
}

F.24 dian

题意

给你n张牌,每张牌的大小为1 ~ 13,问这些牌与加减乘除任意组合(可以使用括号),且但所有的有效解在计算过程中都涉及到分数,即非整数,能否组成答案m,如果可以,输出所有牌的情况

思路

因为 n n n的值不超过 4 4 4,所以我们只需列举所有情况,若结果不等于 m m m或不符合规则便舍去。

代码

/*
 * @Author: Icey_dying
 * @Date: 2021-08-26 21:35:22
 * @LastEditors: Icey_dying
 * @LastEditTime: 2021-08-26 22:21:23
 * @FilePath: \Icey_dying\competition\2021\2021.07\2021.07.24\F.cpp
 */
#include <bits/stdc++.h>
#define lowbit(x) x & -x
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf = 0x3f3f3f3f;
const int N = 1e6 + 100;
const double eps = 1e-6;
int n, m, ans, as[N][5];
double a[5];
int flag;
int sgn(double x) {
    if (fabs(x) <= eps) return 0;
    else if (x < 0) return -1;
    else return 1;
}
bool check(double x) {
    x -= (int)x;
    return sgn(x) != 0;
}
void dfs(int step, int state) {
    if (flag == 3) return ;
    if (step == 4) {
        if (sgn(a[1] - m) == 0) {
            if (state) flag |= 1;
            else flag |= 3;
        }
        return;
    }
    double A[5];
    for (int i = 1; i <= 4; i++) A[i] = a[i];
    for (int i = 1; i <= n - step + 1; i++) {
        for (int j = 1; j <= n - step + 1; j++ ){
            if (i == j) continue;
            for (int k = 1; k <= 4; k++) {
                int nstate = state;
                if (k == 1) a[i] += a[j];
                else if (k == 2) a[i] -= a[j];
                else if (k == 3) a[i] *= a[j];
                else if (k == 4) {
                    a[i] /= a[j];
                    nstate |= check(a[i]);
                }
                swap(a[j], a[n - step + 1]);
                dfs(step + 1, nstate);
                for (int i = 1; i <= 4; i++) a[i] = A[i];
            }
        }
    }
}
void dfs1(int step, int pre) {
    if (step > 4) {
        flag = 0;
        dfs(1, 0);
        if (flag == 1) {
            ans++;
            for (int i = 1; i <= 4; i++) as[ans][i] = a[i];
        }
        return;
    }
    for (int i = pre; i <= 13; i++) {
        a[step] = i;
        dfs1(step + 1, i);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    if (n <= 3) return 0 * puts("0");
    dfs1(1, 1);
    cout << ans << endl;
    for (int i = 1; i <= ans; i++) {
        for (int j = 1; j <= 4; j++) {
            printf("%d ", as[i][j]);
        }
        puts("");
    }
    return 0;
}

J.Counting Triangles

题意

给定一个完全无向图,边的值为0或1,找出有多少个不同的(a,b,c)满足a,b,c三个顶点相互连成的边的值相同

思路

我们可以遍历有多少个点对不是符合题意的三角形,不符合题意的三角形的边可能为0,0,1或0,1,1
对于每一个点来说,我们可以将除它外的点分为两类,边值为0和边值为1,这两类点互相不可能成为三角形。这样的话,我们将所有点遍历一遍之后,不可能成为三角形的点对都重复了2次(比如0,0,1,对于0来说,一个为0,一个为1,有两个,对于1来说,都为0,不记录),所以计数除2。总共的三角形点对数为 C n 3 C_{n}^{3} Cn3,减去刚计算出的数即可。

代码

#include <bits/stdc++.h>
namespace GenHelper
{
    unsigned z1,z2,z3,z4,b,u;
    unsigned get()
    {
        b=((z1<<6)^z1)>>13;
        z1=((z1&4294967294U)<<18)^b;
        b=((z2<<2)^z2)>>27;
        z2=((z2&4294967288U)<<2)^b;
        b=((z3<<13)^z3)>>21;
        z3=((z3&4294967280U)<<7)^b;
        b=((z4<<3)^z4)>>12;
        z4=((z4&4294967168U)<<13)^b;
        return (z1^z2^z3^z4);
    }
    bool read() {
      while (!u) u = get();
      bool res = u & 1;
      u >>= 1; return res;
    }
    void srand(int x)
    {
        z1=x;
        z2=(~x)^0x233333333U;
        z3=x^0x1234598766U;
        z4=(~x)+51;
      	u = 0;
    }
}
using namespace GenHelper;
using namespace std;
int zhen[8005],jia[8005];
bool edge[8005][8005];
int main() {
    int n, seed;
    cin >> n >> seed;
    srand(seed);
    for (int i = 0; i < n; i++)
        for (int j = i + 1; j < n; j++)
            edge[j][i] = edge[i][j] = read();
    long long cnt=0,cnt1,cnt2;
    for(int i=0;i<n;i++){
        cnt1=cnt2=0;
        for(int j=0;j<n;j++){
            if(i!=j){
                if(edge[i][j]==1) cnt1++;
                else cnt2++;
            }
        }
        //cout<<cnt1<<' '<<cnt2<<endl;
        cnt+=cnt1*cnt2;
    }
    long long ans=(long long)n*(n-1)*(n-2)/6-cnt/2;
    cout<<ans<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值