作物杂交
题目描述
作物杂交是作物栽培中重要的一步。已知有𝑁种作物 (编号 1 至𝑁 ),第 𝑖 种作物从播种到成熟的时间为 𝑇𝑖 。作物之间两两可以进行杂交,杂交时间取两种中时间较长的一方。如作物 A 种植时间为 5 天,作物 B 种植时间为 7 天,则 AB 杂交花费的时间为 7 天。作物杂交会产生固定的作物,新产生的作物仍然属于 𝑁 种作物中的一种。
初始时,拥有其中𝑀 种作物的种子 (数量无限,可以支持多次杂交)。同时可以进行多个杂交过程。求问对于给定的目标种子,最少需要多少天能够得到。
如存在 4 种作物 ABCD,各自的成熟时间为 5 天、7 天、3 天、8 天。初始拥有 AB 两种作物的种子,目标种子为 D,已知杂交情况为 A × B → C,A × C → D。则最短的杂交过程为:
第 1 天到第 7 天 (作物 B 的时间),A × B → C。
第 8 天到第 12 天 (作物 A 的时间),A × C → D。
花费 12 天得到作物 D 的种子。
输入描述
输入的第 1 行包含 4 个整数 𝑁,𝑀,𝐾,𝑇,𝑁 表示作物种类总数 (编号
1 至 𝑁),𝑀表示初始拥有的作物种子类型数量,𝐾 表示可以杂交的方案数,𝑇 表示目标种子的编号。
第 2 行包含𝑁 个整数,其中第𝑖个整数表示第 𝑖 种作物的种植时间
𝑇𝑖(1≤𝑇𝑖≤100)
第 3 行包含 𝑀 个整数,分别表示已拥有的种子类型 𝐾𝑗 (1≤𝐾𝑗≤𝑀),𝐾𝑗 两两不同。
第 4 至 𝐾 + 3 行,每行包含 3 个整数 𝐴,𝐵,𝐶,表示第 𝐴 类作物和第
𝐵 类作物杂交可以获得第 𝐶 类作物的种子。
其中,1≤𝑁≤2000,1≤𝐾≤105,1≤𝑇≤𝑁, 保证目标种子一定可以通过杂交得到。
输出描述
输出一个整数,表示得到目标种子的最短杂交时间。
输入输出样例
输入
6 2 4 6
5 3 4 6 4 9
1 2
1 2 3
1 3 4
2 3 5
4 5 6
输出
16
样例说明
第 1 天至第 5 天,将编号 1 与编号 2 的作物杂交,得到编号 3 的作物种子。
第 6 天至第 10 天,将编号 1 与编号 3 的作物杂交,得到编号 4 的物种子。
第 6 天至第 9 天,将编号 2 与编号 3 的作物杂交,得到编号 5 的作物种子。
第 11 天至第 16 天,将编号 4 与编号 5 的作物杂交,得到编号 6 的作物种子。
总共花费 16 天。
#include<bits/stdc++.h>
using namespace std;
const int N = 2010;
typedef pair<int, int> PII;
int w[N], f[N];
bool have[N];
vector<PII> fa[N];
int dfs(int t)
{
for(int i = 0; i < fa[t].size(); i++)
{
int a = fa[t][i].first, b = fa[t][i].second;
if(!have[a]) dfs(a);
if(!have[b]) dfs(b);
if(have[a] && have[b])
{
have[t] = true;
f[t] = min(f[t], max(w[a], w[b]) + max(f[a], f[b]));
}
}
return f[t];
}
int main()
{
int n, m, k, t;
cin >> n >> m >> k >> t;
memset(f, 0x3f3f, sizeof f);
for(int i = 1; i <= n; i++) cin >> w[i];
for(int i = 1; i <= m; i++)
{
int temp;
cin >> temp;
have[temp] = true;
f[temp] = 0;
}
for(int i = 1; i <= k; i++)
{
int a, b, c;
cin >> a >> b >> c;
fa[c].push_back({a, b});
}
cout << dfs(t);
return 0;
}
7月4日晚
2523: 我在大东软的学生名片
题目描述
希望在热身赛里的各位在正赛中都能取得优异的成绩~ 祝大家有个快乐的小学期~
输入
无
输出
Happy practice semester
样例输入 复制
无
样例输出 复制
Happy practice semester
#include<bits/stdc++.h>
using namespace std;
int main(){
int i,j,k;
printf("Happy practice semester\n");
return 0;
}
2524: 金铲铲之战 (弱化版)
题目描述
在一个遥远的王国里,金铲铲是至高无上的荣誉象征,只有最聪明的战士才能获得它。今天,王国将举办一场选拔赛,只有通过智慧和策略的考验,才能赢得金铲铲。需要输入参赛者的姓名strN(有且仅有zmx、hyf、lh、ctb、bb)和选择的答案strM(有且仅有jin、chan)
输入
共一行,为两个字符串strN和strM,用空格隔开
输出
如果strM为"jin" 则输出"wow You got a golden shovel shovel !" 如果strM为"chan"则需判断参赛者: 要是参赛者是"lh"则输出"mystery guest !" 否则输出"regrettably"
样例输入 复制
ctb jin
样例输出 复制
wow You got a golden shovel shovel !
题解
这道题纯sb,出的题目有问题,而且没有换行不给过,整的我无语
#include<bits/stdc++.h>
using namespace std;
string strN,strM;
int main(){
int i,j,k;
cin>>strN>>strM;
if(strM=="jin")
printf("wow You got a golden shovel shovel !\n");
else{
if(strN=="lh")printf("mystery guest !\n");
else printf("regrettably\n");
}
return 0;
}
2525: 数组切割
题目描述
你有一个包含 n 个整数 a1,a2,a3,……的数组,保证 n 是偶数。
现在请你将这个数组分成 n/2 段,定义第 i 段的值 f(i) 为 i * (a_l + a_(l+1) + … + a_(r - 1) + a_r),l 为第 i 段左端点,r为第 i 段右端点。
换句话说,第 i 段的值 f(i) 为 (该段的元素和 * i)。 现在求 f(1) + f(2) + … + f(n/2) 的最大值是多少
输入
第一行包含一个整数 n (1 <= n <= 1e5) —— 数组的大小
第二行包含 n 个整数 a1,a2,…an (-1e9 <= ai <= 1e9) —— 数组的元素
输出
输出一个整数,代表 f(1) + f(2) + … + f(n/2) 的最大值
样例输入 复制
6
6 -8 4 9 11 -10
样例输出 复制
36
提示
最优方法为 [6, -8], [4], [9, 11, -10]
f(1) = 6 - 8 = -2
f(2) = 2 * (4) = 8
f(3) = 3 * (9 + 11 - 10) = 30
f(1) + f(2) + f(3) 最大值为 36
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
i64 ans = 0;
for (int i = 0; i < n; i++) {
std::cin >> a[i];
ans += a[i] * (i + 1);
}
i64 res = 0;
std::vector<int> v;
for (int i = n - 1; i > 0; i--) {
i64 now = res + a[i];
res += a[i];
v.push_back(now);
}
sort(v.begin(), v.end());
for (int i = 0; i < n / 2; i++) {
ans -= *v.begin();
v.erase(v.begin());
}
//2525
2526: 平方数
题目描述
给定一个长度为N的非负整数序列 A=(A1,…,AN) 。求出满足以下两个条件的整数对 (i,j)的数量:
1≤ i < j ≤ N
Ai与Aj乘积为平方数。
当非负整数 a 可以使用某个非负整数 b 表示为 a=b2 时,非负整数a称为平方数。
输入
第一行给定一个N表示非负整数序列A的长度
第二行N个数,表示A序列
2 <= N <= 1e5
0 <= Ai<= 1e5
输出
一个非负整数,表示最终答案
样例输入 复制
5
0 3 2 8 12
样例输出 复制
6
题解
这道题数据范围10^5实际上根本没有到!
基本上都是两层循环来解决这道题的
真正的算法如下:
对于所有的平方数,对于答案的贡献为0,所以可以直接删掉,然后我们根据剩下的来组合,得到最终的结果
#include<bits/stdc++.h>
using namespace std;
int n,a[100005],ans;
int main(){
int i,j,k;
cin>>n;
for(i=1;i<=n;i++)
cin>>a[i];
for(i=1;i<=n;i++){
for(j=i+1;j<=n;j++){
int x=a[i]*a[j];
int sq=sqrt(x);
if(sq*sq==x)ans++;
}
}
cout<<ans<<endl;
return 0;
}
2527: 最少硬币数量组合
题目描述
给定三种不同面额的硬币,以及一个目标金额。
请设计一个算法,计算出用这些硬币组合成目标金额所需的最少硬币数量。
如果无法凑出目标金额,则返回 -1。
输入
第一行包含三个整数,分别表示三种硬币的面额 a, b, c。
第二行包含一个整数 n,表示目标金额。
输出
输出一个整数,表示凑出目标金额所需的最少硬币数量。
如果无法凑出目标金额,输出 -1。
样例输入 复制
1 5 10
18
样例输出 复制
5
提示
样例解释:使用1个10元硬币,1个5元硬币和3个1元硬币,总共需要1+1+3 = 5个硬币可以凑出18元。
- 每种硬币的数量没有限制。
- 保证输入的硬币面额互不相同。
- 题目保证 0 < n < 1000, 0 < a, b, c < 100;
- 尽量优化你的算法,以确保在给定的输入范围内高效运行。
题解
动态规划
2528: 字符串的前后缀
题目描述
给你两个由小写英文字母组成的字符串 S 和 T 。 S 和 T 的长度分别为 N 和 M 。当 T 的前 N 个字符与 S 相同时, S 就可以说是 T 的前缀。 当 T 的后 N 个字符与 S 相同时, S 就可以说是 T 的后缀。
如果 S 既是 T 的前缀,又是 T 的后缀,则打印 0 ; 如果 S 是 T 的前缀,但不是后缀,则打印 1 ; 如果 S 是 T 的后缀,但不是前缀,则打印 2 ; 如果 S 既不是 T 的前缀,也不是后缀,则打印 3 。
输入
第一行,包含两个整数 N 和 M(1≤N≤M≤100)
第二行,包含一个长度为 N 的字符串 S
第三行,包含一个长度为 M 的字符串 T
输出
根据题意输出
样例输入 复制
3 7
abc
abcdefg
样例输出 复制
1
题解
模拟
#include<bits/stdc++.h>
using namespace std;
int n,m;
char a[105],b[105];
int main(){
int i,j,k;
cin>>n>>m>>a+1>>b+1;
int flag1=1,flag2=1;
for(i=1;i<=n;i++){
if(a[i]!=b[i])flag1=0;
}
for(j=1,i=m-n+1;i<=m;i++,j++){
if(a[j]!=b[i])flag2=0;
}
if(flag1==1&&flag2==1)printf("0\n");
if(flag1==1&&flag2==0)printf("1\n");
if(flag1==0&&flag2==1)printf("2\n");
if(flag1==0&&flag2==0)printf("3\n");
return 0;
}
2529: 这是一道莫比乌斯反演问题
题目描述
有这样一个函数 f(x, y),x 和 y 为正整数,定义 f(x, y) 为(x + y)除以 10^8 的 余数
给你一个长度为 n 的正整数序列 a,让你求出下面表达式的值:
(注意:并没有让你计算总和除以 108 的余数)
输入
第一行,包含一个正整数 n(2≤n≤3×105)代表序列的长度
第二行,包含 n 个正整数的集合 a(1≤ai<108)
输出
输入一个数,表示表达式的结果
样例输入 复制
3
3 50000001 50000002
样例输出 复制
100000012
提示
样例解释:
f(a1 , a2) = 50000004
f(a1 , a3) = 50000005
f(a2, a3) = 3
因此,答案为 f(a1 , a2) + f(a1 , a3) + f(a2, a3) =100000012
题解
这道题难,需要考虑到数学思想
首先,我们不计算%10^8的问题,所有的数相加,应该每个都出现了n-1次,先相加
之后我们将数组排序,使用双指针
i指针在前为当前的数字,j为寻找到ai+aj相加大于10^8 的数子位置,由于数组 已经排序,所以之后的一定相加之和大于10^8,所以我们只需要减掉之后的数字即可
signed main()
{
cin >> n;
int res = 0;
for (int i = 1; i <= n; i ++ )
{
cin >> a[i];
res += a[i] * (n - 1);
}
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; i ++ )
{
int l = i + 1, r = n + 1;
while (l < r)
{
int mid = l + r >> 1;
if (a[i] + a[mid] >= mod) r = mid;
else l = mid + 1;
}
res -= (n - l + 1) * mod;
}
cout << res << endl;
return 0;
} //oj 2529
2530: 三角形里的正方形
题目描述
在一个二维平面上有三个点A(a, 0), B(0, b), C(0, 0), 求ACB三点构成的三角形内含有多少个面积为1的正方形,不足一整个正方形的,超过该正方形一半面积就算1个正方形。例如当 a=8,b=6时有24个正方形
输入
两个非负整数a, b (1≤a≤106), (1≤b≤106)
输出
正方形个数
样例输入 复制
6 8
样例输出 复制
24
题解
这道题也是考察数学
首先从左向右搜索,计算从右边看的梯形中计算心昂对应的高度,如果大于0.5则属于,否则不属于
所有相对应的数字相加,得到最终的答案
2531: 小学题,考公题,你试试不?
题目描述
这是一道小学真题
5,3=28
7,6=55
4,5=21
a,b=?
输入
输入两个正整数a和b(0<a,b<=100)
输出
输出一个正整数c
样例输入 复制
5 3
样例输出 复制
28
题解
本题规律题目,不要把规律想的太复杂 c=a*a+b;
#include<bits/stdc++.h>
using namespace std;
int main(){
int i,j,k;
int a,b;
cin>>a>>b;
cout<<a*a+b<<endl;
return 0;
}
2532: 鼓励题!尽可能大的三位数
题目描述
输入一个三位数的正整数,将数字位置重新排列,组成一个尽可大的三位数。例如:输入213,重新排列可得到尽可能大的三位数是321。
输入
三位数的正整数。
输出
重排后尽可能大的三位数。
样例输入 复制
213
样例输出 复制
321
#include<bits/stdc++.h>
using namespace std;
int x,a[10],n=1;
int main(){
int i,j,k;
cin>>x;
while(x){
a[n++]=x%10;
x/=10;
}
sort(a+1,a+1+3);
for(i=3;i>=1;i--)
printf("%d",a[i]);
return 0;
}