2021牛客暑期多校训练营3

2021牛客暑期多校训练营3

B . Black and white

思路:将 n 行 n 列看成2n个点构成的图。每当涂黑点(i , j)时 ,在 i , j+n间建立无向边。最后题目要求的结果是所有矩形涂黑,相当于一个完全联通图。可以发现魔法操作并不改变图的联通性。因此完全联通图与最小生成树在结果上等价。vector桶排序加kruskal在O(\(n^2\))时间内可以完成。

#include<bits/stdc++.h>
using namespace std;
#define  mp make_pair
#define REP(i,a,b) for(int i=a;i<b;i++)
typedef  long long LL ;
typedef unsigned long long Uint;
typedef __int128 LLL;
typedef pair<int, int> P;
const int maxn =5003*5003;
const LL MOD = 1e9+7;
const int INF = 1e9+7;
const double PI = acos(-1);
const double eps = 1e-5;



struct Node
{
    int u, v;
    Node( int u = 0, int v  = 0) : u(u) , v(v) {}
};

LL a, b, c,d, p;
int n , m;
int num[maxn];

int f[20000];

int Find(int x)
{
     return x==f[x] ? f[x] :  f[x]= Find( f[x]);
}


vector<Node> Edge[100005];




void solve()
{

    cin  >> n >> m>> a >> b >>c >> d >>p;
    REP(i , 0 , n)
    REP(j , 0  ,m)
    {
        a = ( a * a * b + a * c + d ) %p;
        Edge[a].push_back(Node( i, j+n));
    }
    REP(i , 0, m+n+100)
        f[i] = i;
    LL ans = 0;
    REP(i , 0 , p)
    {
        for(auto c:Edge[i])
        {
            int  u = c.u;
            int v = c.v;
            int x= Find(u);
            int y = Find(v);
            if(x!=y)
            {
                f[x] = y;
                ans =  ans + i;
            }
        }
    }

    printf("%lld", ans);



}

int main()
{

    ios::sync_with_stdio(false);
    solve();


    return 0;
}


C . Minimum grid

思路:将行列上的最大值排序。按照从大到小遍历。以当前值所限制的行和列作为点,如果行和列所交汇的点可以填数,则在对应行和列之间建边。我们想要所填的数之和尽量小,就希望当前最大值能够尽可能多的被同时被行使用也被列使用。相当于在所建图上找到最大的二分图匹配。二分图上每条边都代表填的这个数同时满足列行的限制和列的限制。每一次ans += ( 当前限制值行的个数 + 当前限制值列的个数 - 二分图最大匹配个数) * 当前限制值。当所有限制值跑完之后,表示之后的数都可以任意填写,因此全部填0对最后结果没有贡献。

#include<bits/stdc++.h>
using namespace std;
#define  mp make_pair
#define REP(i,a,b) for(int i=a;i<b;i++)
typedef  long long LL ;
typedef unsigned long long Uint;
typedef __int128 LLL;
typedef pair<int, int> P;
const int maxn =2e3+4;
const LL MOD = 1e9+7;
const int INF = 1e9+7;
const double PI = acos(-1);
const double eps = 1e-5;
int n, m, k;

vector<int>G[maxn*2];
int vis[maxn*2];
int match[maxn*2];

int vex[maxn][maxn];

vector< int > row[1000005];
vector<int> clo[1000005];

bool Found(int x)
{
    for(auto v:G[x])
    {
        if(vis[v]) continue;
        vis[v] = 1;
        if(!match[v] || Found(match[v]))
        {
            match[v] = x;
            return 1;
        }
    }
    return 0;
}

void solve()
{

    cin >> n >>m >> k;
    for(int i=1;i<=n;++i)
    {
        int tem;cin >>tem;
        row[tem].push_back(i);
    }
    for(int i=1;i<=n;++i)
    {
        int tem;cin >> tem;
        clo[tem].push_back(i+n);
    }
    for(int i=1;i<=m;++i)
    {
        int u ,v;cin >> u >> v;
        vex[u][v] = 1;
    }
    LL ans = 0;
    for(int i=k;i>=1;--i)
    {
        if( row[i].size() ==0 || clo[i].size()==0  )
        {
            ans = ans +  ( 1LL*row[i].size() +clo[i].size()  ) * 1LL*i;
            continue;
        }
        for(int j=0;j<=n+n;++j) G[j].clear();
        for( auto u : row[i])
        {
            for(auto v:clo[i])
            {
                if(vex[u][v-n])
                {
//                    printf(" u = %d  , v=  %d\n", u, v);
                    G[u].push_back(v);
                    G[v].push_back(u);
                }
            }
        }
        LL pipei = 0;
        memset(match, 0, sizeof match);
        for(int k = 1 ; k<=n;++k)
        {
            memset(vis, 0  ,sizeof vis);
            if(Found(k)) pipei++;
//         printf("i = %d k = %d  ,   pipei = %lld, \n", i , k , pipei);
        }
        ans = ans+  ( 1LL*row[i].size() +clo[i].size() - 1LL*pipei ) * 1LL*i;
//        printf("ans =%lld\n", ans);
    }
    printf("%lld\n", ans );

}

int main()
{
    ios::sync_with_stdio(false);
    solve();
    return 0;
}


J . Counting Triangles

思路:如果三点不能构成一个三角形, 一定是有一个点上的两条边颜色不同。我们考虑计算不合法的三角形个数。记录每个点标号为1的边的度数。对于这个点所构成的不合法三角形就是( 度数 ) * ( n - 度数)/2。对与每个点都减去不合法的三角形最后得出的就是答案。


#include<bits/stdc++.h>
using namespace std;
#define  mp make_pair
#define REP(i,a,b) for(int i=a;i<b;i++)
typedef  long long LL ;
typedef unsigned long long ULL;
typedef pair<int, int> P;
const int maxn =8e3+5;
const LL MOD = 1e9+7;
const int INF = 1e9+7;
const double PI = acos(-1);
const double eps = 1e-7;

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;
bool edge[8005][8005];
int deg[8005];
int main() {
  LL n;int seed;
  cin >> n >> seed;
  srand(seed);
  for (int i = 0; i < n; i++)
    	for (int j = i + 1; j < n; j++)
        {
            int  tem =read();
                deg[j]+=tem;
                deg[i]+=tem;
        }
    LL ans = n * (n -1) * (n-2) /6;
    for(int i=0;i<n;++i)
    {
        ans -= deg[i] * ( n - 1 - deg[i])/ 2;
    }
    cout << ans;
 	return 0;
}

posted on 2021-07-25 17:02  安乐最值钱  阅读(52)  评论(0)    收藏  举报

导航