0704暑假集训前的欢乐大杂烩总结

0704暑假集训前的欢乐大杂烩总结

在TM迎接暑假超级无敌20天happy乐的前夕来了一场巨多人的超级爽的欢乐赛
然而老刘的数据翻车了 (所以我们在这里就暂且不去论第5题)

T1 --质因数分解

【正解】:我都不想说什么,爆0是最骚的。这么睿智的一道题我居然GG了,平时的板子要去多多复习啊。(话说我自己还写过相应的博客啪啪

重点
被分解的数在long long范围内
这题后来订正的时候,枚举质因子时我是

for(int j=2;j*j<=p;j++)
 .....

但是这样会爆j的int范围导致失去部分分数。
所以我们得注意定义一个int级的变量时,如果有乘法要么将变量还是改成ll,或者在乘法加上(1LL)* 或者前面加上(long long)
【注意不是加在后面,不然前面已经炸了再加上就没什么意义了,我的T6最后一个点就是因为加在后面然后GG了】

T2—蛇形方阵2

【正解】每一圈k的起点必定是(k,k),然后再按顺时针逆时针去模拟就可以了,比较水。

T3—大采购

【正解】多重背包板子,注意二进制拆分操作。
(好吧,现在已经是单调队列了,谁还用二进制拆分?)

T4—吉波 鸡脖 那切数列

【问题描述】
有⼀个很著名的数列叫做斐波那契数列,它的定义式是
Fn = Fn−1 + Fn−2
其中,递推的初始值为:F0 = 1, F1 = 1
在吉波那契数列这个问题中,我们相似地定义了⼀个吉波那契数列 Gn:
Gn = Gn−1 + Gn−2
对任何情况⽽⾔,G0 = 1, ⽽ G1 是⼀个随机的正整数 t。
现在告诉你 Gi 的值和两个正整数 i, j,请你求出 Gj。鉴于 Gj 可能很⼤,
请你输出 Gj mod 19960515。
【输入格式】
输⼊⽂件名为 gibonacci.in
有多组测试数据。第⼀⾏是⼀个正整数 T,表示测试数据的组数。
接下来 T ⾏,每⾏为⼀组测试数据,每组测试数据包含 3 个正整数 i, Gi
, j。
【输出格式】
输出⽂件名为 gibonacci.out
对于每组数据,输出 Gj mod 19960515。
假如没有合适的 t,请输出 −1。
【样例输入】
2
1 1 2
3 5 4
【样例输出】
2
8
【数据规模与约定】
对于 30% 的数据,每个 Gibonacci 数列的 G1 = t ≤ 50
对于 50% 的数据,有 T ≤ 30
对于 100% 的数据,有 T ≤ 10000, 1 ≤ i, j ≤ 100000, 0 ≤ Gi < 19960515

不妨设G1=x
则序列可变为:1,x,x+1,2x+1,3x+2,5x+3,8x+5…
发现x的系数满足斐波那契数列,常数项也满足斐波那切数列,那么已知Gi便可以知道它的x系数和常数项,看看x能否得出是正整数即可。
然后以此得出Gj的x系数和常数项然后就OK
别忘了取模%%%

code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int q=19960515;
int f[100010],t;
int main()
{
	freopen("gibonacci.in","r",stdin);
	freopen("gibonacci.out","w",stdout);
   scanf("%d",&t);
   f[0]=0;
   f[1]=f[2]=1;
   for(int i=3;i<=100000;i++)
     f[i]=(f[i-1]+f[i-2])%q;
   while(t--)
   {
   	int x,y,c,w;
   	ll num;
	scanf("%d%lld%d",&x,&num,&y);
    c=f[x-1];
	w=f[x];
	if((num-c)%w||num-c<0) printf("-1\n");
	else 
	{
		int g=((num-c)/w)%q;
		printf("%lld\n",(((1LL)*f[y]*g)%q+f[y-1])%q);
	} 
   }
   return 0;
}

T5—魔塔

由于这道题老刘翻车了,利用记忆化搜索dfs会有漏洞,而正解是什么IDA*加堆优化,于是我暂且先不去谈%%%(其实是我不会
老刘别打我 在这里插入图片描述

T6—对战

【题面】
对战
(inhouse.cpp/c/pas)
【问题描述】
在⼀条街道上有 n 个⼈,他们都喜欢打乒乓球。任意两个⼈的家的位置都
不相同,按顺序标为 1, 2, · · · , n。每个⼈都有⼀定的⽔平,用两两不等的整数表
示。
当两个⼈想打球的时候,会找另⼀个⼈作为裁判,并到裁判家里进⾏⼀场
较量。出于某种原因,他们希望裁判的⽔平介于两⼈之间;同时,他们希望两个
⼈到裁判家的总路程不超过两个⼈的家的距离。
对于两场较量,如果打球的两个⼈不完全相同或者裁判不同,我们就认为
这两场较量不同。求不同的较量的总数。
【输入格式】
输⼊⽂件名为 inhouse.in
输⼊包含多组数据
输⼊的第⼀⾏是⼀个整数 T,表示数据组数;
每组数据占⼀⾏,包含 n + 1 个整数:n, a1, a2, · · · , an。其中 a1, a2, · · · , an
表示家位于相应位置的⼈的⽔平。
【输出格式】
输出⽂件名为 inhouse.out
对每组数据,用⼀⾏输出⼀个整数,表示不同的较量的总数。
【样例输入】
1
3 1 2 3
【样例输出】
1
【数据规模与约定】
对于 40% 的数据,有 n ≤ 1000;
对于所有数据,有 T ≤ 20, 3 ≤ n ≤ 100000,每个⼈的⽔平都是不超过200000 的正整数。

【正解】一开始看到题想到使用双指针指向两个互相对决的人,然后累加他们之间合法的裁判,发现这样就十分暴力,时间复杂度高。
正难则反的思想:枚举2~n-1个人去做裁判,看看能给多少组人去当裁判即可。
明显只需知道裁判i左边比他高的L1[i],右边比他低的R1[i],左边比他矮的L2[i],右边比他高的R2[i]
答案就是SUM(L1[i]*R2[i]+L2[I]*R1[i]) 2<=i<=n-1
那么现在的问题就是如何快速得到这个L1,R1,L2,R2;
用树状数组维护这种关系,类似逆序对的求法,只需要减一减就OK了。

code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll t,maxx=-1;
ll a[100501],c[200101];
ll lef1[105001],righ1[100501],lef2[100501],righ2[100501];;

void add(ll x,ll val)
{
	for(;x<=maxx;x+=x&-x)
	  c[x]+=val;
}

ll sum(int x)
{
	ll ans=0;
	for(;x;x-=x&-x)
	  ans+=c[x];
	return ans;
}
int main()
{
	freopen("inhouse.in","r",stdin);
	freopen("inhouse.out","w",stdout);
  scanf("%d",&t);
  while(t--)
  { int n;
  	scanf("%lld",&n);
  	ll ans=0;
	maxx=-1;
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]),maxx=max(a[i],maxx);
  	for(ll i=1;i<=n;i++)
   {
   	lef1[i]=sum(a[i]-1); 
    lef2[i]=lef1[i];//左边比他低
   	lef1[i]=i-1-lef1[i];	//左边比他高
	add(a[i],1);
   }
   memset(c,0,sizeof(c));
   for(ll i=n;i>=1;i--)
   {
   	righ1[i]=sum(a[i]-1);
   	righ2[i]=righ1[i];//右边比他低
   	righ1[i]=n-i-righ1[i];//右边比他高
	add(a[i],1);
   }
   for(ll i=2;i<n;i++)
     ans+=(ll)(lef1[i]*righ2[i]),ans+=(ll)(lef2[i]*righ1[i]);//注意这(ll)
   printf("%lld\n",ans);
   memset(c,0,sizeof(c));
  }
}

前面已经提过,你原本以为的int不会爆,但是相乘就可能会GG,所以保险起见还是加上一个(ll)或者
1LL*;不过要加在乘法运算的前面

总结:因为爆int失分高达30,因为板子忘记敲失分100分。细节处理失分10分。然后魔塔就不说了,直接GG了。这启示我,int乘法加(ll)是必须的,板子多去敲敲,不复习就真的GG,功在平时;
细节处理也很重要,思路要更缜密一些。

Summer Holiday Training,I’m Coming !

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值