水题略。
#include
#include
#include
using namespace std;
int main()
{
int T;
cin >> T;
while(T--)
{
int n, X;
cin >> n >> X;
int a;
int suma = 0; // 总学分
int b;
for(int i = 0; i < n; i++)
{
cin >> a;
suma += a;
}
bool flag = true;
double sum = 0; // 成绩学分加权和
for(int i = 0; i < n; i++)
{
cin >> b;
sum += (((double)b * (double)a) / (double)suma);
if(b < 60)
{
flag = false; // 有不及格的课
break;
}
}
if(flag == false) cout << "NO" << endl;
else
{
if(sum >= X) cout << "YES" << endl;
else cout << "NO" << endl;
}
}
return 0;
}
题目要求所有给出的数可以两两组成一对和相等(target)的面,没有一个数是多余的。那么一定符合一个最小的数加一个最大的数正好等于target,一个次小的数加一个次大的数正好等于target……的规律。
所以方案是先给 n 个数排序,两端同步向内遍历,判断两数之和是否相等。
#include
#include
#include
using namespace std;
bool canMakeDice(int n, vector<int>& nums) {
sort(nums.begin(), nums.end()); // 将数字从小到大排序
int sum = 0;
for (int i = 0; i < n; i++) {
sum += nums[i];
}
int target = sum / (n/2);
int left = 0, right = n-1;
while (left < right) { // 从两端向中间遍历,如果两端数字之和不等于 target,说明不能构成骰子
if (nums[left] + nums[right] != target) {
return false;
}
left++;
right--;
}
return true;
}
int main() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> nums(n);
for (int i = 0; i < n; i++) {
cin >> nums[i];
}
if (canMakeDice(n, nums)) {
cout << "YES" << endl;
} else {
cout << "NO" << endl;
}
}
return 0;
}
贪心。将每种作物的性价比排序,性价比相同的话将需要时间较少的作物放在前面。然后从性价比高的作物开始,计算最多可以种多少这种作物以获得更多收益(注意,题目说了可以重复购买一种作物的种子),当剩余天数不满足需要的天数时,按性价比顺序找下一种剩余时间还可以种的作物,直到将所有作物遍历完。
#include
#include
#include
using namespace std;
struct Node { // 作物
double rate; // 性价比(收益/时间)
int needDay; // 需要的时间
int money; // 收益(卖出价格-买入价格)
};
bool cmp(Node a, Node b) { // 给每种作物的性价比排序,性价比相同的话将需要时间较少的作物放在前面
if (a.rate == b.rate) {
return a.needDay < b.needDay;
}
return a.rate > b.rate;
}
int main(){
int n, m;
cin >> n >> m;
vector<Node> v; // 作物
int t[2005], a[2005], b[2005];
for (int i = 0; i < n; i++) {
cin >> t[i];
}
for (int i = 0; i < n; i++) {
cin >> a[i];
}
for (int i = 0; i < n; i++) {
cin >> b[i];
}
for (int i = 0; i < n; i++) {
Node node;
node.money = b[i] - a[i];
node.rate = (double)node.money / (double)t[i];
node.needDay = t[i];
v.push_back(node);
}
sort(v.begin(), v.end(), cmp); // 给作物性价比排序
int maxMoney = 0; // 最大收益
int nowDay = 0; // 当前所用时间
int index = 0; // 当前作物的下标
while (index < n && nowDay < m) {
if (nowDay + v[index].needDay <= m) { // 只要当前时间加上这种作物需要的时间不超过总时间,就尽可能多地买排在前面的性价比高的作物
maxMoney += v[index].money;
nowDay += v[index].needDay;
} else {
index++;
}
}
cout << maxMoney << endl;
return 0;
}
前(后)缀数组。
先计算后缀和数组 suf,suf[i] 表示删掉从 i 到字符串末尾的后缀,并保留字符串剩余部分所需的操作代价;
然后计算最小代价后缀数组 minsuf,minsuf[i] 表示删掉从 i 或之后任意位置到字符串末尾的后缀,并保留字符串剩余部分所需的操作代价的最小值;
最后遍历所有可能删掉的前缀,加上对应的最小代价后缀,比较选取总代价的最小值。
#include
#include
#include
using namespace std;
int main()
{
string s;
cin >> s;
int n = s.size();
vector<int> suf(n + 1, 0); // suf[i]后缀和数组:表示删掉从 i 到字符串末尾的后缀,并保留字符串剩余部分所需的操作代价
int sum1 = 0, sum0 = 0;
for(int i = 0; i < n; i++)
{
sum1 += s[i] - '0'; // 整个字符串1的个数
}
sum0 = n - sum1; // 整个字符串0的个数
suf[n] = sum0;
for(int i = n - 1, sum00 = sum0, sum11 = sum1; i >= 0; i--)
{
if(s[i] == '1') {
suf[i] = suf[i + 1] + 1;
sum1--;
}
else {
suf[i] = suf[i + 1] - 1;
}
}
vector<int> minsuf(n + 1, 100000); // minsuf[i]表示删掉从 i 或之后任意位置到字符串末尾的后缀,并保留字符串剩余部分所需的操作代价的最小值
int minn = 100000;
for(int i = n - 1; i >= 0; i--)
{
minn = min(minn, suf[i]);
minsuf[i] = minn;
}
int ans = 100000;
for(int i = 0, temp = 0; i < n; i++)
{
ans = min(ans, temp + minsuf[i]); // temp表示删掉 i-1 及其之前的前缀,并保留字符串剩余部分所需的操作代价;用temp加上i之后的最小后缀和,就是删掉当前前缀和最小代价后缀的总代价;遍历所有前缀的情况,ans取最小值
if(s[i] == '1') temp++;
else temp--;
}
cout << ans << endl;
return 0;
}
分治法。
递归将参赛者不断两两分组,直到分到一人一组,将小组的胜者层层返回,上层的小组再将两胜者比较。
#include
#include
#include
#include
using namespace std;
int winner(vector<vector<int>> &v, int begin, int end)
{
if(begin == end) return begin; // 只有一个人,返回他的编号
int a = winner(v, begin, (begin + end) / 2); // 前半段比赛
int b = winner(v, (begin + end) / 2 + 1, end); // 后半段比赛
return v[a][b]; // a 和 b 比赛,a 胜利返回 a,b 胜利返回 b
}
int main()
{
int k;
cin >> k;
int n = pow(2, k);
vector<vector<int>> v(n + 1, vector<int>(n + 1, 0));
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
cin >> v[i][j];
}
}
cout << winner(v, 1, n) << endl;
return 0;
}