Minimum grid
题意
给出了一个n*n的矩阵,和矩阵中的一些位置,要求我们再这些位置中填数使得满足每一行的最大值满足b[i],每一列的最大值满足c[i];要求填的数之和最小。
对于这个问题,我们最大的数就是将每一行每一列的数都加起来,由于要求最小,所以我们要尽可能找到一个点,使它所在的每一行每一列均满足最大,由于一个点的值只有一个,所以它的行和列的最大值应该相同。这样,我们就可以从行和列的最大值入手,找出有多少个这样的点,我们每找出这样一个点,就相当与减少了这个最大值在最后结果中的贡献,这样,我们将这个最大值的行和列提取出来分别放在两个点集中,如果对应的这些点可以连成一条边(也就是在矩阵中a[i][j]是可填数的)每连上这样一条边,就可以减少这个最大值在矩阵中的贡献,由于最小,所以我们所求的就是这个行列的最大匹配(二部图每连一条线,我们所填的最大值就可以减少一个);对于每一个最大值,都有以它为最大值的【(行数+列数-二部图边数)*最大值】这样的贡献,最后对于每一个最大值都跑一个二部图的匹配,将所有最大值的贡献相加就是答案了(最大值从小到大,从大到小遍历都是可以的)
#include<vector>
#include<iostream>
#include<memory.h>
using namespace std;
#define int long long
const int M = 1000010;
const int N = 2010;
int mp[N][N];
vector<int>b[M],c[M];
int link[N];
int vis[N];
vector<int>to[N];
int dfs(int x)
{
for(auto y : to[x])
{
if(vis[y]) continue;
vis[y] = 1;
if(!link[y] || dfs(link[y]))
{
link[y] = x;
return 1;
}
}
return 0;
}
int x,y;
signed main(){
int ans=0;
int n,m,k;
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
cin>>x;
b[x].push_back(i);
}
for(int i=1;i<=n;i++){
cin>>x;
c[x].push_back(i);
}
for(int i=1;i<=m;i++){
cin>>x>>y;
mp[x][y]=1;
}
for(int i=1;i<=k;i++){
if(b[i].size()==0&&c[i].size()==0)continue;
for(int j=1;j<=n;j++)to[j].clear();
for(auto j:b[i]){
for(auto z:c[i]){
if(mp[j][z]==1)to[j].push_back(z);
}
}
int res = 0;
for(int j = 1;j <= n;++j)
{
memset(vis,0,sizeof vis);
res += dfs(j);
}
ans += (b[i].size() + c[i].size() - res) * i;
}
cout<<ans<<endl;
}
Counting Triangles
(太长了不想贴图了)
题意
按照题目要求给了一个二维矩阵,数出这里面所有的三条边全为同样颜色的三角形个数
由于数出这样的三角形的个数比较难,所以我们可以换成另一种想法,用这些点所能形成的三角形个数减去含有异边的三角形个数
对于每个含异边的三角形,我们可以(惊讶的)发现,这些三角形一定是有两条同边一条异边的,也就是说,它一定是有两个异角,一个同角的,所以含有异边的三角型的个数一定是 异角的个数/2 用可以形成的三角形的个数减去含异角的三角形的个数,就是答案;
#include<iostream>
#include<vector>
#include<algorithm>
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];
long long w[8005];
long long bl[8005];
using namespace std;
int main() {
long long n;
int 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 ans = n * (n - 1) * (n - 2) / 6;//一共可以形成多少个三角形;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if(i==j)continue;
if (edge[i][j] == 1)w[i]++;
else bl[i]++;
}
}//统计不同角的个数;
long long sum = 0;
for (int i = 0; i < n; i++)sum += bl[i] * w[i];//异色角的数量;
ans = ans - sum / 2;
cout << ans << endl;
return 0;
}
Math
就这样枚举上去由于数据范围是1e18,我们就需要选择离线算出,然后排序,最后二分输出答案(注意这里最后会有1e18*1e18,long long 是存不住的需要用__int128;
#include<bits/stdc++.h>
using namespace std;
const long long maxn = 1e7 + 10;
vector<long long>a(maxn);
int sum=0;
void init(){
a[sum] = 1;
sum++;
for (long long i = 2; i <= 1000000; i++) {
__int128 x = i * i * i;
__int128 k = i;
while (x <= 1000000000000000000) {
a[sum] = x;
sum++;
__int128 p = x;
x = x * i * i - k;
k = p;
}
}
sort(a.begin(), a.begin()+sum);
}
int main() {
init();
int t;
cin >> t;
while (t--) {
long long n;
cin >> n;
int ans = lower_bound(a.begin(), a.begin()+sum, n) - a.begin();
if (a[ans] == n)cout << ans + 1 << endl;
else cout << ans << endl;
}
}
Black and white
题意
有一个二维nm的cost矩阵,里面的cost满足cost[i][j]满足A(m(i-1)+j);其中A(0)=a,A(i+1)=(Ai * Ai * b + Ai * c + d)% p,其中我们每将三个黑色的方块涂黑,剩下的一个方块会自动涂黑,所以我们最少可以只在每一行每一列选择一个格子涂上黑色,通过这个选法生成一个最小生成树,这个最小生成树的权值和就是我们需要消耗的代价;然后跑一遍Prim或者是Kruskal求出权值和就行了
#include <bits/stdc++.h>
using namespace std;
const int N=5010;
const int M=3e7+10;
int A[M],fa[2*N];
struct node{
int x,y;
long long w;
bool operator < (const node & u) const { return w < u.w; }
}p[M];
const int INF=0x3f3f3f3f;
int n, m, a, b, c, d, e;
int find(int x){
if(fa[x]!=x)fa[x]=find(fa[x]);
return fa[x];
}
int js(long long x) {
return (x * x * b + x * c + d) % e;
}
void jd(){
A[0]=a;
int flag=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
flag=m*(i-1)+j;
A[flag]=js(A[flag-1]);
p[flag]={i,j,A[flag]};
}
}
}
void solve(){
cin>>n>>m>>a>>b>>c>>d>>e;
jd();
long long res=0,cnt=m+n-1;
for(int i=1;i<=n+m;i++)fa[i]=i;
sort(p+1,p+m*n+1);
for(int i=1;i<=m*n;i++){
int x=p[i].x;
int y=p[i].y;
long long w=p[i].w;
x=find(x);
y=find(n+y);
if(!cnt)break;
if(x!=y){
fa[x]=y;
cnt--;
res+=w;
}
}
cout<<res<<endl;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin.exceptions(ios::badbit | ios::failbit);
solve();
}
需要注意的是,内嵌的小于号重载会比cmp函数快上不少
24dian
题意
题目的意思是给我没1~13的数字,这些数字可以出现多次,要求我们将这些数字进行四则运算,同一种运算可以出现多次,但必须包含小数也就是除法,问我们到达结果 k 有多少种途径,这些途径是什么;用dfs模拟就好了,需要用到两个dfs,一个遍历所有的值,一个遍历四则运算,在结果处判断是否有除法出现以及是否等于结果,将满足情况的统一到一个数组中,输出它的长度以及它的值就好了。
还有就是要注意,可能会有除零这种情况发生,在除法的时候要判断一下。
#include <bits/stdc++.h>
using namespace std;
const int N=5010;
const int M=3e7+10;
const double mix=1e-12;
const int INF=0x3f3f3f3f;
vector<vector<int>>ans;
vector<int>zj;
bool v[10],flag=0,yy;
double a[5];
int n,k;
bool c(double x){
return x-(int)x*1.0<mix;
}
//判断是否为整数
bool cmp(double x) {
return fabs(x) < mix;
}
//判断大小
void dfss(int p,bool d){
if(p==n){
if(fabs(a[0]-k)<mix){
if(d==1)yy=1;
else flag=0;
}
return;
}//四则运算后是否等于k
for(int i=0;i<n;i++)if(c(a[i])==0)d=1;//是否是分数
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(v[i]||v[j])continue;
double x=a[i],y=a[j];
v[j]=1;
a[i]=x+y;
dfss(p+1,d);
a[i]=x*y;
dfss(p+1,d);
a[i]=fabs(x-y);
dfss(p+1,d);
if (!cmp(x))a[i] = y / x, dfss(p + 1, d);
if (!cmp(y))a[i] = x / y, dfss(p + 1, d);
v[j]=0;
a[i]=x,a[j]=y;
}
}//遍历四则运算
}
void dfs(int s,int x){
if (s == n) {
flag=1;
yy=0;
memset(v,0,sizeof(v));
dfss(1,0);
if(flag==1&&yy==1){
zj.clear();
for(int i=0;i<n;i++)zj.push_back(a[i]);
ans.push_back(zj);
}
return;
}
for (int i = x; i < 14; i++) {
a[s] = i;
dfs(s + 1, i);
}
}//主dfs将所有值所对应的情况遍历,s记录多少层,x记录对应的值;
void solve(){
cin >> n >> k;
if (n < 4) {
cout << 0 << endl;
return;
}//n小于四时是没有答案的,特判;
dfs(0, 1);
cout << ans.size() << endl;
for(int i=0;i<ans.size();i++){
for(int j=0;j<ans[i].size();j++){
cout<<ans[i][j]<<" ";
}
cout<<endl;
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin.exceptions(ios::badbit | ios::failbit);
solve();
}