2021暑期牛客多校训练3

J-Counting Triangles

在这里插入图片描述

思维题,正难则反

思路:

看到此题的第一反应通常是搜索,但会超时,优化的话也会超时。

题目要求三边颜色相同的三角形,那么可以将所有的三角形的个数减去三边颜色不完全相同的三角形的个数即可得到答案。

所有的三角形的个数: C n 3 = n ∗ ( n − 1 ) ∗ ( n − 1 ) / 6 C_n^3=n*(n-1)*(n-1)/6 Cn3=n(n1)(n1)/6

三边颜色不完全相同的三角形的个数:将每个点相连的黑边的个数和白边的个数相乘再相加,最后除以2(每个三角形会被重复数一次)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define rep1(i,a,b) for(int i=a;i<b;i++)
#define pre(i,a,b) for(int i=a;i>=b;i--)
#define pre1(i,a,b) for(int i=a;i>b;i--)
#define pep(i,stl) for(auto i:stl)
#define INF 0x7fffffff
#define eps 1e-6
#define mem(a,b) memset((a),(b),sizeof(a))
const int N=2e6+5;
const int mod=1e9+7;
const double PI = acos(-1);
#define pep(i,stl) for(auto i:stl)
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;
int d[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++){
    		int k = read();
    		d[i]+=k;d[j]+=k; 
		}
    ll ans=0;
	rep(i,0,n-1)
    ans+=1ll*d[i]*(n-d[i]-1);
    cout<<1ll*n*(n-1)*(n-2)/6-ans/2;
 	return 0;
}

E-Math

在这里插入图片描述

思路:打表推导

通过打表发现满足条件的x,y有些还满足 y = x 3 y=x^3 y=x3​,

并且对于不满足该条件的(x,y)数对呈现多组的x与y首位相同连成序列的形式,即:

8—30—112—418—1560

27—240—2133

于是任务就是要找到序列的递推式

x y + 1 ∣ x 2 + y 2 xy+1|x^2+y^2 xy+1x2+y2​可写成 x 2 + y 2 = k ( x y + 1 ) x^2+y^2=k(xy+1) x2+y2=k(xy+1)

y 2 − k x y + x 2 − k = 0 y^2-kxy+x^2-k=0 y2kxy+x2k=0​​

由韦达定理易得 k x = y 1 + y 2 kx=y_1+y_2 kx=y1+y2

可得 y 2 = k x − y 1 y_2=kx-y_1 y2=kxy1

y 1 = 0 y_1=0 y1=0时, k = x 2 , y 2 = x 3 k=x^2,y_2=x^3 k=x2,y2=x3

即将x代入上式时方程有两个解, y 1 = 0 , y 2 = x 3 y_1=0,y_2=x^3 y1=0,y2=x3 ,题目要求y>=x,所以有 ( x , x 3 ) (x,x^3) (x,x3)

同时也可以理解为当 x = x 3 x=x^3 x=x3​ 时,x为其中的一个解;(当 x = x , y = x 3 x=x,y=x^3 x=x,y=x3​时, x y + 1 ∣ x 2 + y 2 ​ xy+1|x^2+y^2​ xy+1x2+y2成立;当 x = x 3 , y = x x=x^3,y=x x=x3,y=x​时, x y + 1 ∣ x 2 + y 2 xy+1|x^2+y^2 xy+1x2+y2​也成立,可以将x和y互换)

再将 x 3 x^3 x3​代入上式,求得 y 2 = k x 3 − x y_2=kx^3-x y2=kx3x(x为其中的一个解)

以此类推:(x,y)(y,ky-x) k = x 2 k=x^2 k=x2

得到递推式后,在数据范围内不断递推y的值,并且记录在数组中,找到所有的y值后,将数组排序,在对输入的值做二分查找便可输出答案

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define rep1(i,a,b) for(int i=a;i<b;i++)
#define pre(i,a,b) for(int i=a;i>=b;i--)
#define pre1(i,a,b) for(int i=a;i>b;i--)
#define pep(i,stl) for(auto i:stl)
#define INF 0x7fffffff
#define eps 1e-6
#define mem(a,b) memset((a),(b),sizeof(a))
const int N=2e6+5;
const int mod=1e9+7;
const double PI = acos(-1);
#define pep(i,stl) for(auto i:stl)
ll n,m;
ll arr[N];
int main() {
	int t,cnt=0;
	cin>>t;
	arr[cnt++]=1;
	rep(i,2,1000000){
		ll x=i,y=x*x*x,k=x*x;
		arr[cnt++]=y;
		while(y<=(1e18+x)/k){
			ll tem=y;
			y=k*y-x;
			x=tem;
			arr[cnt++]=y;
		}
	}
	sort(arr,arr+cnt);
	while(t--){
		scanf("%lld",&n);
		printf("%d\n",upper_bound(arr,arr+cnt,n)-arr);
	}  
 	return 0;
}

B-Black and white

在这里插入图片描述

题目意思理解有误导致比赛时WA了无数发,哎。。。。。

For the four intersecting squares of any two rows and two columns, if three of them are black squares, Goodeat can dye the fourth square black without any cost.

对于任意两行两列的四个相交正方形,如果其中三个是黑色正方形,Goodeat可以免费将第四个正方形染成黑色。

这里的四个相交正方形是指任意的两行和任意的两列相交产生的四个正方形,而不是指四个挨在一起的正方形

思路:MST

四个相交正方形中任意三个是黑色,另外一个自动成黑色;

考虑行列之间的连通性,若 ( i , j ) , ( i + 1 , j ) , ( i , j + 1 ) (i,j),(i+1,j),(i,j+1) (i,j),(i+1,j),(i,j+1)均为黑色,则i与j连通,i与i+1连通,j与j+1连通,可得i+1与j+1连通;

即对于某一点来说,若该点的行坐标与列坐标连通则该点免费变黑

即对n+m个点找最小生成树

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define rep1(i,a,b) for(int i=a;i<b;i++)
#define pre(i,a,b) for(int i=a;i>=b;i--)
#define pre1(i,a,b) for(int i=a;i>b;i--)
#define pep(i,stl) for(auto i:stl)
#define INF 0x7fffffff
#define eps 1e-6
#define mem(a,b) memset((a),(b),sizeof(a))
const int N=3e7+5;
const int mod=1e9+7;
const double PI = acos(-1);
#define pep(i,stl) for(auto i:stl)
ll n,m,a,b,c,d,p,cnt;
int fa[N],ans=INF;
int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
struct edge{
	int s,e,v;
	bool operator<(const edge &d)const{
		return v<d.v;
	}
}e[N];
int main() {
	cin>>n>>m>>a>>b>>c>>d>>p;
	rep1(i,0,n){
		rep1(j,0,m){
			a=(a*a*b+a*c+d)%p;
			e[cnt].v=a;e[cnt].s=i;e[cnt++].e=j+n;
		}
	}
	sort(e,e+cnt);
	rep1(i,0,n+m) fa[i]=i;
	int t=0;a=0;
	rep1(i,0,cnt){
		if(find(e[i].s)!=find(e[i].e)){
			fa[find(e[i].e)]=find(e[i].s);
			a+=e[i].v;t++;
		}
		if(t==n+m-1) break;
	}
	cout<<a;
 	return 0;
}

F-24dian

在这里插入图片描述

思路:dfs搜索

题目给定n个数,这n个卡片通过加减乘除运算得到特定值m且在运算过程中必须形成分数,问有多少种方案并按字典序输出

注意:某方案中的n个数可能通过多种加减乘除运算顺序得到特定值m,所以要记录算出m的方法数和算出m而且出现过分数的方法数.两者一样的n个数才符合题意。特判分母为0

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define rep1(i,a,b) for(int i=a;i<b;i++)
#define pre(i,a,b) for(int i=a;i>=b;i--)
#define pre1(i,a,b) for(int i=a;i>b;i--)
#define pep(i,stl) for(auto i:stl)
#define INF 0x7fffffff
#define eps 1e-9
#define mem(a,b) memset((a),(b),sizeof(a))
const int N=3e7+5;
const int mod=1e9+7;
//const double eps=1e-8;
const double PI = acos(-1);
#define pep(i,stl) for(auto i:stl)
int n,m,f,cnt; 
ll ans;
double num[5];
int number[300000][5],tem[5];
bool vis[5];
bool judge(double a,double b){
	if(a>(int)a+eps||b>(int)b+eps||a/b>(int)(a/b)+eps) return 1;
	return 0;
}
void dfs(int x,bool t,int now){
	if(x==n-1){
		if(fabs(num[now]-m)<1e-8)
		{
			f++;
			if(t) cnt++;
		}
	}
	else{
		rep(i,0,n-1)
		rep(j,0,n-1){
			if(i^j&&!vis[i]&&!vis[j]){
				double c=num[i],d=num[j];
				int mi=min(i,j),ma=max(i,j);
				vis[mi]=1;
				num[ma]=c+d;
				dfs(x+1,t,ma);
				num[i]=c,num[j]=d;
				num[ma]=c*d;
				dfs(x+1,t,ma);
				num[i]=c,num[j]=d;
				num[ma]=c-d;
				dfs(x+1,t,ma);
				num[i]=c,num[j]=d;
				if(d){
					num[ma]=c/d;
					dfs(x+1,t|judge(c,d),ma);
					num[i]=c,num[j]=d;
				}
				vis[mi]=0;
			}
		}
	}
}
void ds(int x,int m){
	if(x==n){
		f=0;cnt=0;
		dfs(0,0,0);
		if(f==cnt&&f>0){
			ans++;
			rep(i,0,n-1)
			number[ans][i]=tem[i];
		}
	} 
	else{
		rep(i,m,13)
		tem[x]=num[x]=i,ds(x+1,i);
	}
}
int main() {
	cin>>n>>m;
	if(n<3){
		cout<<0;return 0;
	}
	ds(0,1);
	cout<<ans<<endl;
	rep(i,1,ans){
		rep(j,0,n-1)
		cout<<number[i][j]<<' ';
		puts("");
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值