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;
}
浙公网安备 33010602011771号