比赛:
http://oj.hzjingma.com/contest/view?id=69
试题A:生存还是毁灭,这是一个问题(字符串遍历)
试题B:小小神枪手 开局98K(数学:概率论)
试题C:关云长单刀会金莲,贾宝玉三打白骨精(组合数学或者暴力枚举)
试题D:抽刀断水水更流,举杯销愁愁更愁(二进制枚举)
试题E:左手作圆右手方,世人机敏便可尔(数学计算)
试题F:等差等比有联系 公差公比求通项(思路 + 模拟 + 快速幂)
试题G:进退得失全看透,名利当作粪土丢(贪心)
试题H:映日圆光万颗余,如观宝藏隔虾须(BFS,不懂思路,知道要用BFS)
试题I:自知无奈的回绝,奇迹是否能够出现(不会)
试题J:世界末日的时候,我会牵着你的手(不会)
利用编程,读入,依此遍历,统计字母个数。最后输出字母个数最大值
#include
using namespace std;
int cnt[30], A[30];
int main()
{
memset(cnt, 0, sizeof(cnt));
memset(A, 0, sizeof(A));
string s;
vector passages;
freopen("input.txt", "r", stdin);
while(cin >> s)
{
passages.push_back(s);
}
for(auto p : passages)
{
for(int i = 0;i < p.size(); ++i)
{
// 不区分大小写
if(p[i] >= 'a' && p[i] <= 'z') ++cnt[p[i] - 'a'];
if(p[i] >= 'A' && p[i] <= 'Z') ++cnt[p[i] - 'A'];
}
cout << endl;
}
int res = 0;
for(int i = 0;i < 26; ++i)
{
res = max(res, cnt[i]);
}
cout << res << endl;
return 0;
}
根据期望的计算公式:。其中在这里,V 是射击次数,P 是对应的概率
当 V = 1 时,也就是说,第一枪中了,那么概率是 0.75
当 V = 2,第一枪不中,第二枪中,那么概率是 (1 - 0.75) * (0.75 * 0.9)
当 V = 3,第一、二枪都不中,第三枪中,那么概率 (1 - 0.75) * (1 - 0.75 * 0.9) * (0.75 * 0.9 * 0.9)
直到射中概率 < 0.5 为止。
那么在程序中,也就是一个变量记录 第几次射击,一个变量记录前几次都不中(也就是不断的累成,上一次不中的概率),一个变量记录 这一次 中的概率。(期望就是,每一个的 涉及次数 * 这次的概率的累加)
#include
using namespace std;
int main()
{
int cnt = 1; // 第几次射击
double res = 0;
double get = 0.75; // 这次中的概率
double p = 1; // 前几次都不中概率
while(get >= 0.5)
{
res += p * get * cnt; // 第几次射击时的期望累加
++cnt; // 射击次数增加
p *= (1.0 - get); // 相当于上一次不中,也就是累乘不中概率
get *= 0.9; // 这次中的概率
}
printf("%0.6lf\n", res);
return 0;
}
思路一、组合数学
也就是将 四大名著需要的时间看成一个整体,也就是 5,4,3,3,各自看成一个整体,那么剩下还有 16 天(这 16 天有 17个空),那么插入的时候,总共的可能为:17 * 18 * 19 * 20 = 116280。(一开始是 17 个空,插入一个 ;18个空,再插入一个;19个空,插入一个;20个空,最后插入一个)
思路二、暴力枚举
我们通过枚举每一个名著的开始阅读时间,然后判断这种可能方案,满不满足要求。也就是每一本名著读书的那天,不能读其他的。
我们可以用一个变量 vis,记录每一天是否已经读过了,如果已经读过,我们还读,那么这个方案就不可能。
#include
using namespace std;
bool isCan(int a, int b, int c, int d)
{
int vis[40];
memset(vis, 0, sizeof(vis)); // 记录 31 天的读书情况
for(int i = 0; i < 5; ++i) vis[a + i] = 1; // 第一本名著 5 天
for(int i = 0;i < 4; ++i) // 第二本 4 天
{
if(vis[b + i] == 1) return false; // 如果这天已经读了,那么就不能再读了
vis[b + i] = 1;
}
for(int i = 0;i < 3; ++i)
{
if(vis[c + i] == 1) return false;
vis[c + i] = 1;
}
for(int i = 0;i < 3; ++i)
{
if(vis[d + i] == 1) return false;
vis[d + i] = 1;
}
return true;
}
int main()
{
int cnt = 0;
for(int a = 1; a <= 27; ++a) // 5
{
for(int b = 1; b <= 28; ++b) // 4
{
for(int c = 1; c <= 29; ++c) // 3
{
for(int d = 1;d <= 29; ++d) // 3
{
if(isCan(a, b, c, d)) ++cnt;
}
}
}
}
cout << cnt << endl;
return 0;
}
总共 22 个数,选择其中的 0 -12 个数,加上来组成一个新数。
我们可以用二进制枚举,对于 22 个数,每一个数,只有拿或不拿两种情况,也就是 0 或者 1。所以总共有 2 ^ 22 约等于 4e6。不会超时。
因为我们用二进制枚举,每一位对应这个数要不要取,如果取,那就累和。还要注意,最后只能取 12 个,所以我们要判断,这种取法中 1 的个数,如果是 >12 ,那这种方案不成立。
然后算出所有情况的数,用 set 统计(可能有重复的,去重)。
最后答案是问,无法构成的个数,因此答案是 : 总数(1695) - set 中的数(可以构成了这么多数)
#include
using namespace std;
int nums[22] = {3,5,7,11,13,19,23,29,31,37,41,53,59,61,67,71,97,101,127,197,211,431};
set recd;
int main()
{
recd.clear();
int lim = (1 << 22);
for(int i = 0;i < lim; ++i)
{
int cnt = 0;
int res = 0;
int tep = i;
for(int j = 0;j < 22; ++j)
{
if((tep >> j) & 1)
{
++cnt;
res += nums[j];
}
}
if(cnt <= 12)
{
recd.insert(res);
}
}
int cnt = 1695;
cout << cnt - recd.size() << endl;
return 0;
}
根据题目要求,也就是计算值,我们通过画图可以发现
也就是一个三角形的面积的四倍,一个扇形面积的四倍。
三角形的面积好求,两条边,勾股定理求底,然后 S = 1 / 2 * 底 * 高
对于扇形面积 : ,其中θ是弧度制的角度,我们可以通过求三角形的那个角度的弧度(cosA = 4 / 3),得到 A 之后,我们发现 A + A + θ = PI / 2。那么就可以求出 θ了。
剩下就是代码求数值了
#include
using namespace std;
const double PI = 3.14159265358979;
int main()
{
double res = 3.0 * sqrt(7.0) + 8.0 * (PI / 2.0 - 2.0 * acos(3.0 / 4.0));
printf("%0.2lf\n", res);
return 0;
}
我们通过 v1 = b / a, v2 = c / b。因为要最大,所以要求出来的公比 q 尽可能的大
其中, v1 和 v2 应该是,找到一个最大的 q 的幂都满足可以 = v1,和 = v2。
几个特殊情况 :
1)当 b = a,或者 c = b 的时候,那么公比就是 q = 1
2)如果 v1 == v2,那么直接 q = v1 即可。
剩下的情况就是,我们已经知道 v1(将 v1 和 v2 中的最小值保存在 v1 中),不会是 公比,那么最大的可能应该是从 开方开始找(因为不会是 q = v1,那么为了使得 q 尽可能大,那么 q ^ 2 = v1,q = sqrt(v1),一直到 2 ,枚举 q)
当判断出 这个 q 和 v1,v2 都是幂的关系(也就是比如,q ^ x = v1,也就是说,v1 % q == 0,一直到 v1 == 1为止。不然就是不满足 q ^ x = v1 )
最后得到 公比 q 之后,那么第 N 项,根据公式,就是 an = a1 * q ^ (n - 1)。
由于 n 的数据范围,所以我们要使用快速幂进行解决。
#include
using namespace std;
#define LL long long
const LL MOD = 1e9;
LL qpow(LL x, LL y)
{
LL ans = 1;
while(y)
{
if(y & 1) ans = ans * x % MOD;
x = x * x % MOD;
y >>= 1;
}
return ans;
}
bool isCan(LL x, LL y) // x == y ^ n
{
while(x)
{
if(x == 1) return true;
if(x % y != 0) return false;
x /= y;
}
}
int main()
{
LL a, b, c, N;
cin >> a >> b >> c >> N;
if(a == b || a == c) cout << a << endl;
else
{
LL res = 0, q = 0;
LL v1 = b / a, v2 = c / b;
if(v1 > v2) swap(v1, v2);
if(v1 == v2) q = v1;
else
{
q = v1;
int temp = sqrt(v1);
for(int i = temp + 1; i >= 2; --i)
{
if(isCan(v1, i) && isCan(v2, i))
{
q = i;
break;
}
}
}
res = a * qpow(q, N - 1) % MOD;
cout << res << endl;
}
return 0;
}
我们对于某一个天的需求,这个时候可能还有前几天的剩货,那么先用剩货补货。
如果补货了,还差,那就要新买
而对于买,由于可以提起买,我们就找,这一天以及前面的所有最便宜的(这样子使得花费最小,而且是可以的,因为这样子,我们相当于是提前在前面买的)。
所以,对于购买价格,我们一直是找,这一天以及前面的所有价格中的最小值来购买即可。
要特别注意的,由于买一盒柠檬是得到 5 * 16 = 80 片,所有要注意。同时,对于要新买的柠檬,如果不能被 80 整除,说明我们要多买一点儿,同时这样子,会有剩货(要记录)
#include
using namespace std;
#define LL long long
int main()
{
LL n, a, b;
cin >> n >> a >> b;
LL miPa = 1000, miPb = 1000;
LL hasPa = 0, hasPb = 0;
LL res = 0;
for(int i = 0;i < n; ++i)
{
LL c, pa, pb;
cin >> c >> pa >> pb;
miPa = min(miPa, pa);
miPb = min(miPb, pb);
res += c * a * miPa;
if(hasPb >= c * b) // 剩货超过需要的,那么不需要重新买
{
hasPb -= c * b;
}
else // 否则,说明不够,要重新买
{
LL needPb = c * b - hasPb;
hasPb = 0;
if(needPb % 80 == 0)
{
res += (needPb / 80) * miPb;
}
else
{
LL tep = (needPb / 80) + 1; // 不被整除,说明多买一盒
res += tep * miPb;
hasPb = tep * 80 - needPb; // 多出来的剩货,要记录
}
}
}
cout << res << endl;
return 0;
}
这道题,知道是用BFS,但是不知道思路是怎么样的。
代码可以看链接,其他人提交的,但是不知道思路,所以看不太懂。
代码可以看链接,其他人提交的,但是不知道思路,所以看不太懂。
代码可以看链接,其他人提交的,但是不知道思路,所以看不太懂。