2021暑假牛客多校3

本文探讨了在黑白棋盘上放置棋子的最优化策略,涉及排列组合与集合论,解析了如何通过韦达定理解决数学问题,并展示了复杂 dfs 模拟在解决实际问题中的应用,同时研究了图论中的三角形计数问题,涉及边的颜色分布及其影响。
摘要由CSDN通过智能技术生成

B.Black and white

题意:
一个nxm的白色棋盘,在上边放上黑棋,放黑棋是有代价的,但是如果两行两列的四个焦点中有三个已经放上了,另外一个可以不花费任何代价放上该枚棋子,问放满棋盘的最小代价为多少?
A(i+1) = (Ai * Ai * b + Ai * c + d)% p
Where A(m*(i-1)+j) is the cost c(i, j)

主要思路:
根据题目要求先求出来每个位置的棋子代价(不要开数组,会越界)。然后分析可得,可以将行和列看作是点,放上一个棋子就相当于将i,j加入一个集合中。若某个棋子的i,j已经为一个集合了,则不用花费代价。

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pa;
const int N=1e6+10;
vector<pa> a[N];
int f[N];
int find(int k)
{
    if(f[k]==k) return k;
    return f[k]=find(f[k]);
}
int main()
{
    int n,m,b,c,d,p;
    ll aaa;//注意数据范围
    cin>>n>>m>>aaa>>b>>c>>d>>p;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            aaa=(aaa*aaa%p*b+aaa*c%p+d)%p;
            a[aaa].push_back({i,j+n});
        }
    }
    int ans=0;
    for(int i=0;i<=m+n;i++) f[i]=i;
    for(int i=0;i<=p;i++)
    {
        for(int j=0;j<a[i].size();j++)
        {
            int x=a[i][j].first,y=a[i][j].second;
            if(find(x)!=find(y))
            {
                f[find(x)]=find(y);
                ans+=i;
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

E.Math

题意:
给定一个n,问从 1~n 满足 x y + 1 ∣ x 2 + y 2 xy+1|x^2+y^2 xy+1x2+y2(1≤x≤y≤n)的数量。

主要思路:
利用韦达定理,推理出规律(也可打表),利用二分,求出答案。

公式推理:
令x为常数,利用韦达定理可得:
x 2 + y 2 = k ( x y − 1 ) x^2+y^2=k(xy-1) x2+y2=k(xy1)
y 1 + y 2 = k x , y 1 ∗ y 2 = x 2 y_1+y_2=kx , y_1*y_2=x^2 y1+y2=kx,y1y2=x2
x ≤ y 1 x\leq y_1 xy1,则 0 ≤ y 2 0\leq y_2 0y2.
y = k x y=kx y=kx,可得 x 2 + k 2 y 2 = k ( k x 2 + 1 ) , k = x 2 x^2+k^2y^2=k(kx^2+1),k=x^2 x2+k2y2=k(kx2+1)k=x2.
由此可得答案应都形为:
( x , y )   ( x , x 3 )   ( x 2 − 1 , x 4 − x 2 ) . . . . . . . (x,y)~(x,x^3)~(x^2-1,x^4-x^2)....... (x,y) (x,x3) (x21,x4x2).......

!!!注意数据类型,不可为unsigned long long (刚好为1e18,会使判断y大小的条件失效)

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef __int128 ull;
vector<ull> v;
int main()
{
    int t;
    cin>>t;
    for(long long  i=2;i<=1e6;i++)
    {
        ull y=i*i*i,x=i,k=i*i;
        v.push_back(y);
        while(y<=1e18)
        {
            ull xx=y;
            y=k*y-x;
            x=xx;
            if(y<=1e18)
                v.push_back(y);
        }
    }
    sort(v.begin(),v.end());
    while(t--)
    {
        long long n;
        cin>>n;
        cout<<upper_bound(v.begin(), v.end(),n)-v.begin()+1<<endl;
    }
    return 0;
}

F.24dian

题意:
选取n张值(1 ≤ x ≤ 13 \leq x\leq 13 x13)的牌,进行四则运算后(可随意加括号),结果为m的情况,输出(式子中出现小数的)情况数,并且输出每种情况选择的牌。

主要思路:
该题是一个比较复杂的dfs模拟,需要合理利用各种容器。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
const int N=1e6+10;
vector<double> ans[N];
int n,m;
int num;
vector<double> v;
int flag,cnt;
bool judge(double x,double y)
{
    double xx=x/y;
    int xxx=xx;
    if(xx!=xxx) return 1;
    return 0;
}
void dfss(int x,int qwq,vector<double> v)//bianlifuhao
{
    if(x==n)//符号已满
    {
        if(fabs(v[0]-m)<1e-8)
        {
            flag++;
            if(qwq) cnt++;
        }
        return;
    }
    int sz=v.size();
    for(int i=0;i<sz;i++)
    {
        for(int j=0;j<sz;j++)
        {
            if(i==j) continue;
            vector<double> tmp;
            tmp.clear();
            for(int k=0;k<sz;k++)
                if(k!=i&&k!=j)
                    tmp.push_back(v[k]);
                    
            tmp.push_back(v[i]+v[j]);
            dfss(x+1,qwq,tmp);
            tmp.pop_back();
            tmp.push_back(v[i]-v[j]);
            dfss(x+1,qwq,tmp);
            tmp.pop_back();
            tmp.push_back(v[i]*v[j]);
            dfss(x+1,qwq,tmp);
            tmp.pop_back();
            tmp.push_back(v[i]/v[j]);
            dfss(x+1,qwq|judge(v[i],v[j]),tmp);
            tmp.pop_back();
        }
    }
}
bool check(vector<double> v)
{
    flag=0,cnt=0;
    dfss(1,0,v);
    if(flag==cnt&&cnt) return 1;
    return 0;
}
void dfs(int x,int pre)//bianlipai
{
    if(x==n+1)//排满
    {
        if(check(v))
            ans[num++]=v;
        return;
    }
    for(int i=pre;i<=13;i++)
    {
        v.push_back(i);
        dfs(x+1,i);
        v.pop_back();
    }
}
int main()
{
    cin>>n>>m;
    dfs(1,1);
    cout<<num<<endl;
    for(int i=0;i<num;i++)
    {
        int sz=ans[i].size();
        for(int j=0;j<sz;j++) cout<<ans[i][j]<<' ';
        cout<<endl;
    }
    return 0;
}

J.Counting Triangles

题意:
给定一个无向完全图,每条边都染上黑色或白色,问三条边同色的三角形数量。

主要思路:
三角形仅有两种:①三边同色 ②异色,且含有两个异色角。
然后难点是如何计算异色角的个数。答案为三角形总数-异色角数/2
异色角数求法:
若边ij为黑色 b[i]++,b[j]++
若为白色 w[i]++,w[j]++
在i点处的异色角数即为:b[i]*w[i]

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;

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 main() {
    int b[8010]={0},w[8010]={0};
  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();
            if(edge[i][j]) w[i]++,w[j]++;
            else b[i]++,b[j]++;
        }
    ll sum=0;
   ll ans=(ll)n*(ll)(n-1)*(ll)(n-2)/(ll)6;
    for(int i=0;i<n;i++)
        sum+=b[i]*w[i];
    cout<<ans-sum/2<<endl;
 	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值