2021牛客暑期多校训练营3

首先,没有爆0!没有爆0!!没有爆0!!! 差点G了

E Math

首先这道题,没有看懂题目。
原来x2+y2|k(xy+1)的意思是前面可以整除后面???????? 我直接%&¥%*#%(开玩笑)
队友还说是或的意思,人麻了。不过好像公式写反了。自己看原题吧,懒得改了。

Math光速入口!

一开始在手算想要找规律,在进行了十分钟无用功之后忽然想到为啥不用计算机打表,哪怕是打前面的数值较小的表也可以。。

然后就对着若大的一些表看找规律。

大概就相当于
i=2的情况下(2,8)–>(8,30) -->(30,112) -->(112,418) 规律很清晰了有没有
8* 22-2 = 30
3022-8=112
112
22-30=418;
当然 还有i=3,4,5…106 ,为什么是 106呢 因为n最大取值为1018

数据值太大,肯定不能用下标存,直接存数值就好了! 再sort排一个序,搞一个二分查找什么的,完美。(但是我不会写,代码是队友写的,我只有思路

哦,对了 要开__int128 听说 1e18也不会爆。

#include <bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
//#define int unsigned long long
#define int  __int128
#define re int
#define eps 1e-8
#define ls(p) p<<1
#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define mk make_pair
#define P pair < int , int >
using namespace std;
const int N=5e6+5;
int a[N];
inline int read()
{
    int X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
 
 
inline void write(int x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
 
void solve()
{
    int t=0;
    a[++t]=1;
    for(int i=2;i<=2000001;i++)
    {
        int temp1=i*i*i;
        int temp2=i;
        int temp3=0;
        while(1)
        {
            if(temp1>1e18||temp1<0)  break;
            a[++t]=temp1;
            temp3=temp2;
            temp2=temp1;
            temp1=temp2*i*i-temp3; 
        }
    }
    sort(a+1,a+t+1);
    int now;
    now=read();
    while(now--)
    {
        int y;
        y=read();
        int x=upper_bound(a+1,a+t+1,y)-a;
        write(x-1);
        puts("");
    }
}
signed main()
{
    int T=1;      
//    cin>>T;
    for(int index=1;index<=T;index++)
    {
        solve();
//        puts("");
    }
    return 0;
}

J题 Counting Triangles

好了 接下来是J题, 没想到有一天我还有机会看图论的题。

JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ

大概的意思呢就是说,给了你一个完全图,给了你每一条边的颜色,可能是黑色或者白色(具体记不清了,反正是两种),然后就要你求任意三条边连成的三角形是同色的还是异色的。(就是说三条边的颜色是不是一样嘛) 。
在这里插入图片描述
是不是很漂亮。
然后发现直接求是很难求解的,因为被卡了时间复杂度。我们需要在n2的时间复杂度内算出来。
最后是采用一个简单的容斥定理。直接求相同的不好求,那么我们求不同的。遍历每一个节点。那么异色的三角形的个数我们认为是这个节点的红色的边的数量乘以蓝色的边的数量加起来。
把每个节点的都加起来,最后是每个三角形都被计算了两次,然后又因为是完全图,我们很容易算出来所有边的个数的。减去就好了。

#include <bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
#define int long long
//#define double long double
//#define double long long
#define re int
//#define void inline void
#define eps 1e-8
//#define mod 1e9+7
#define ls(p) p<<1
#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define mk make_pair
#define P pair < int , int >
using namespace std;
const int mod=1e9+7;
//const int inf=1e18;
const int M=1e8;
const int N=8e3+5;//??????.???? 4e8
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[N][N];
int v[N];
int ans,cnt;
void solve()
{
    int n, seed;
	int ans=0;
    cin>>n>>seed;
    srand(seed);
    for(re i=1;i<=n;i++)  for(re j=i+1;j<=n;j++)  edge[j][i]=edge[i][j]=read();
    for(re i=1;i<=n;i++)  for(re j=i+1;j<=n;j++)  if(edge[i][j])  v[i]++,v[j]++;
	for(re i=1;i<=n;i++)  cnt+=v[i]*(n-1-v[i]);
	ans=(n-1)*(n-2)*n/6-cnt/2;
	cout<<ans<<endl; 
}
signed main()
{
    int T=1;       
//    cin>>T;
    for(int index=1;index<=T;index++)
    {
        solve();
//        puts("");
    }
    return 0;
}
/*



*/

B题 Black and white

Black and white

本来我想着是只要一条线连着左上角到右下角或者相反就可以补全整个矩形。后来发现存在着一些的问题。如果我是角落的地方都填MAX那不是BUG了么?

后来又想着先找到最小的2*2的方框,然后根据周围的最小值向外扩充。

最后看了题解,二分图。没听说过,就是点亮一个方框(i,j)就相当于链接了第i行和第j列
我们最后也就是要连接出来一个二分图,是连通的二分图。我们优先选择权值比较小,且没有在一个集合中的两个点进行链接。这样,这不是最小生成树么?

用并查集就可以解决了。
这里注意下find函数,要在寻找的过程中进行修改值,这样可以减小很大的时间复杂度不至于超时。

另外P mk pb 宏定义真的很方便 还有auto 开优化真的香 可惜dev不支持编译

#include <bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
#define int long long
//#define double long double
//#define double long long
#define re int
//#define void inline void
#define eps 1e-8
//#define mod 1e9+7
#define ls(p) p<<1
#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define mk make_pair
#define P pair < int , int >
using namespace std;
const int mod=1e9+7;
//const int inf=1e18;
const int M=1e8;
const int N=8e3+5;//??????.???? 4e8

int F[100005]={0};
int a[100005]={0};
vector<P>v[100005];

int fd(int f)
{
	return f==F[f]?f:(F[f]=fd(F[f]));
}

void solve()
{
    int n,m,a,b,c,d,p;
    cin>>n>>m>>a>>b>>c>>d>>p;
    for(re i=1;i<=n+m;i++)F[i]=i;
    for(int i=1;i<=n;i++)
    {
    	for(int j=1;j<=m;j++)
    	{
    		a=(a*a*b+a*c+d)%p;
    		v[a].pb(mk(i,j+n));
		}
	}
	int ans=0;
	for(int i=0;i<p;i++)
	{
		for(auto u:v[i])
		{
			int x=fd(u.first);
			int y=fd(u.second);
			if(x!=y)
			{
				ans+=i;
				F[x]=y;
			}
		}
	}
	cout<<ans<<endl;
}
signed main()
{
    int T=1;       
//    cin>>T;
    for(int index=1;index<=T;index++)
    {
        solve();
//        puts("");
    }
    return 0;
}
/*


*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

while WA er

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值