链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
我惊叹这数学的推导,我遗憾我数学实在学不好QWQ
目录
1.牛牛看云
题目描述:
就像罗夏墨迹测试一样,同一片形状的云在不同人的眼中会看起来像各种各样不同的东西。
例如,现在天上飘过了一片长条状的云彩,hina说这片云长得像是薯条,moca说这片云长得像宾堡豆沙面包(5枚装),kasumi说这片云在闪闪发光,kokoro说这片云怎么看上去不开心呢,牛牛说这片云长得就像是:
现在给出整数序列a,请你帮牛牛求出这个式子的值。
输入描述:
第一行包括一个整数n(3≤n≤),整数序列的长度。
第二行输入n个以空格分隔的整数(0≤
≤1000),表示序列
。
输出描述:
输出一个整数,表示该式子的值。
示例
输入:
4 500 501 500 499
输出:
8
思路:
首先我脑海中浮现一个最简单的两层循环,(这不超时才怪...
良心出题人表示,数据范围些许微妙,一般给的是都是差不多(即都是10^6或是10^9)的,这次为什么<=1000呢?
于是,我们可以开一个1005的数组,记录这个值出现的次数.emmm...为什么记录次数呢?要清楚的是,结果与输入数字的顺序无关,每个数都算了n+1次,
比如,输入 1 2 3 4
就加了(1+1)(1+2)(1+3)(1+4)
(2+2)(2+3)(2+4)
(3+3)(3+4)
(4+4)
接着我们来计算次数:
例如,500 500 500 501 501
那么就有3* 2=6个(500,501)即 ct(500) *ct (501)
但如果 i==j 呢? 如 502 502 502 502
就不能是4*4=16个(502,502)了,用等差数组求和公式吧
因为j 从i的位置往后移,有n个相同的数,依次根自己及后面的组合,就是n+(n-1)+...+1. 也就是
n*(n+1)/2了
#include<iostream>
#include<cmath>
using namespace std;
int n, i, j, t;
long long ans, ct, a[1005];
int main(){
cin >>n;
for(i=0; i < n; i++){
cin >>t;
a[t]++;
}
for(i=0;i<=1000;i++){
for(j=i; j<=1000; j++){
if(i==j)ct=a[i]*(a[i]+1)/2; //可以用等差数组求和得到
else ct=a[i]*a[j];
ans+=ct*abs(i+j-1000);
}
}
cout << ans;
return 0;
}
2.中位数切分
题目描述:
给定一个长为n的数组a和一个整数m,你需要将其切成连续的若干段,使得每一段的中位数都大于等于m,求最多可以划分成多少段。
我们定义,偶数个数的中位数为中间两个数中较小的那一个,奇数个数的中位数就是正中间的数。如[2,3,1,5][2,3,1,5][2,3,1,5]的中位数为2,[2,3,1,2][2,3,1,2][2,3,1,2]的中位数为2,[3,5,9,7,11][3,5,9,7,11][3,5,9,7,11]的中位数为7。
输入描述:
输入第一行是一个整数T(1≤T≤20),测试组数。
每个测试第一行是两个整数n,m(1≤n≤,1≤m≤
),含义如题目所示。
第二行输入n个数,数组a,满足1≤≤
。
由于本题输入量较大,建议使用scanf等高效输入方式。
输出描述:
每个测试用例,输出一个整数,表示最多可以划分成多少段,若无论如何划分都不能满足条件,输出-1。
示例
输入:
4 5 4 10 3 2 3 2 5 3 5 2 3 3 2 2 5 4 5 5 2 10 3 2 3 2
输出:
-1 1 -1 5
此题答案太过惊艳...居然就是...
ct1 - ct2 !!! (ct1为>=m的数的个数,ct2为<m的数的个数,所以干脆写2*ct1 - n吧)
讲题人给了“严谨证明” 和 “简单(不大严谨)证明”,这里就不多说了,挂几个重要结论吧qwq
1.严谨版证明思路:
记 f ( l , r ) 为原数组 中a[l] ...a[r]一段中的 ct1 - ct2 的值;
f ( l , r ) = f ( l , mid) + f ( mid+1 , r )
若f ( l , mid) = 1,则mid 位置可切一刀
2.简易版:
当数组元素全都是 >=m的数时,那么最多可以切分为n(数组长度)段,
插入一个 <m的数时,至少需要两个 >m 的数与其组合为一组,而这俩数原来是单独一段的,于是答案就减少了 1,这时再加入一个 <m的数:(说不清了,举栗子)
一开始 : 5 5 5 5 5 5 ——6段
插入一个2 : (2 5 5) 5 5 5 5 ——6-1=5段
再插入一个2 : 情况一:( 2 2 5 5 5)5 5 5 ——6-2=4段
情况二:那如果2与2不相邻呢? :(2 5 5 ) 5 5(5 5 2)
我们发现,虽然每个2需要两个5,比情况一多消耗了一个5,但它们却是两段(比情况一多一段), 结果也是 6-2=4段
3.炸鸡块君的高中回忆
题目描述:
炸鸡块君在高中时,学校规定进出校门必须要刷校园卡,否则禁止进入。
某一天,炸鸡块君和同学们一共n个人去学校附近玩耍,但回学校时他们发现只有m个人带了校园卡,于是他们想到了这样一个策略:先让m个人带校园卡进入学校,再派一个人带着所有m张校园卡出来,重复上述过程,直到所有人进入学校。
假设从外面进入学校和从校内出来到校外都需要花费一个单位的时间,求所有人都进入学校最少需要花费几个单位的时间。
输入描述:
输入第一行是一个整数T(1≤T≤),表示测试组数。
每组测试包括两个整数n,m(1≤m≤n≤),含义如题目所示。
输出描述:
输出一个整数,表示所有人进入学校需要花费最少几个单位时间。特别的,若无法让所有人进入学校,输出−1。
示例
输入:
3
6 3
10 10
10 1
输出:
5
1
-1
思路:
(我觉着边界不大好处理,就模拟,然后超时了...
结果就一行数学公式,憋说了,看枯了...)
注意到每次进出相当于减少了(m-1)人,当然,最后一次只进不出,进的人数可以小于m,
为了统一,我们假设最后一次进了还会出来,这样就多算了一趟,最后再减一就行,其中跑腿的同学又不一样,我们把他分离出来,除了他,其余人全部进去需要多少次?
见公式:2*( (n-1)/(m-1) + ( (n-1)%(m-1)!=0 ) ) - 1
即,如果(n-1)%(m-1)==0,一层括号里就不用加1,否则多加 1 .
举栗子:n=10,m=4,这时9%3==0,也就是最后还剩3(注意数字特点 :能被9整除)个人时,跑腿的同学再回来,这时校外有4人了,恰好可以一道回校而不出来,而这最后一次是算在(n-1)/(m-1)里的最后一次,是算了来回的,最后乘二减一就刚好,倘若n=11,最后就会剩5人,就得多算个来回。
#include<iostream>
using namespace std;
int t, n, m, ans;
int main(){
cin >> t;
while(t--){
cin >> n>> m;
if(n==m)ans=1;
else if(m==1)ans=-1;
else ans = 2*((n-1)/(m-1)+((n-1)%(m-1)!=0))-1;
cout <<ans <<endl;
}
return 0;
}
可见数学的强大QWQ