A. Chess Placing(模拟)
题目链接:点击打开链接
题目大意:现在有长度为n的格子,n个格子分为两类,奇数格子和偶数格子。
给出n/2个元素的队列,给出他们当前在n个格子中的位置,他们能左右移动,但一个格子只能由一个元素,问最少移动多少次将所给出的所有元素移动到奇数格子或是全部移动到偶数格子。
题目思路:观察的题目的数据范围100,暴力计算奇数和偶数格子的最少步数比较即可
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> pos(n / 2);
for (int i = 0; i < n / 2; ++i)
cin >> pos[i];
sort(pos.begin(), pos.end());
int ans1 = 0, ans2 = 0;
for (int i = 0; i < n / 2; ++i) {
ans1 += abs(pos[i] - (i * 2 + 1));
ans2 += abs(pos[i] - (i * 2 + 2));
}
cout << min(ans1, ans2) << endl;
return 0;
}
B. Switches and Lamps(模拟)
题目链接:点击打开链接
题目大意:n个开关,m栈灯,每个开关控制一些灯。问删除一个开关,能否用剩下的n-1个开关控制所有的灯
题目思路:记录每盏灯会被多少开关控制
然后查找是否有一栈灯只被一个开关控制
#include <bits/stdc++.h>
using namespace std;
#define maxn 5000
#define LL long long
int n,m;
int a[maxn][maxn];
int num[maxn];
char s[maxn];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%s",&s[1]);
for(int j=1;j<=m;j++)
{
a[i][j]=s[j]-'0';
num[j]+=a[i][j];
}
}
int ok=1;
for(int i=1;i<=n;i++)
{
ok=1;
for(int j=1;j<=m;j++)
{
if(a[i][j]==1&&num[j]==1)
{
ok=0;
break;
}
}
if(ok)break;
}
if(ok)printf("YES\n");
else printf("NO\n");
return 0;
}
C. Liebig's Barrels(贪心)
题目链接:点击打开链接
题目大意:给出n个木板,告诉你m个木板可以组成一个桶,桶的装水高度由最短木板的长度决定,并且所有组成的木桶他们的最短木板的两两高度差小于等于l。
求出所有桶的最大装水量和,如果不能组成n个桶,则输出0
题目思路:这题主要是一个贪心的策略。
一开始,将所有ai按非递减顺序排序。
然后计算从第一个最短的木板开始有多少个木板他们的两两高度差满足小于等于l的要求,假设前面有k个木板满足,k如果小于m个直接输出0.
如果k大于等于m,他们肯定是有结果的,接下来就是用贪心的策略来让结果尽可能的大。
因为一个木桶的体积由最小木板决定,所有前面的木桶尽量的选取较短的木板拼凑,让之后的最短木板尽可能的大。
但是注意,m个木桶的最短木板只能在之前找到的前k个木板中查找,我们的贪心就是尽可能的剔除掉k个中较短的,留下较长的。
#include <bits/stdc++.h>
using namespace std;
#define maxn 500000
#define LL long long
int n,k,l;
int a[maxn];
int main()
{
cin>>n>>k>>l;
int len=n*k;
for(int i=1;i<=len;i++)cin>>a[i];
sort(a+1,a+len+1);
int num=1;
for(int i=2;i<=len;i++)
{
if(a[i]-a[1]<=l)
{
num=i;
}
else break;
}
int del=num-n;
if(del<0)
{
printf("0\n");
return 0;
}
LL sum=0;
int cnt=0;
for(int i=1;i<=num;i++)
{
cnt++;
if(cnt>k)cnt=1;
if(cnt==1&&del)
{
sum+=a[i];
}
else if(cnt>1&&del)
{
del--;
}
else if(del==0)
{
sum+=a[i];
}
}
printf("%I64d\n",sum);
return 0;
}
D. Sand Fortress
题目链接:点击打开链接
题目大意:
题目思路:让我们考虑一下最优的答案,总是看起来像h1 ≤ h2 ≤ ... ≤ hk ≥ hk + 1 ≥ ...
k将是一个最大高度的柱子的最左边的位置。我们将大量使用从1到hk的所有整数在这个序列中出现在k的右边。
如果您能够构造任何答案,那么很容易将其重新安排到这个模式:选择最左边的k,排序[1..(k - 1)在非递减的顺序和[k + 1.]中,在非递增的顺序中。排序序列也是有效的。
让高度k的金字塔是一个有效的城堡,它正好占据了2k - 1个连续点,1 = h1 < h2 <…建造它需要的是k2砂包。
最后,可以使用以下算法计算出答案:
1.找出最大值k,在中,其中h1 = min(k, H)。解这个方程或者只做二分查找;
2.输出被截断的金字塔的宽度,加上它将用来分配剩余沙袋的最小数量的额外柱子。
#include <bits/stdc++.h>
#define forn(i, n) for (int i = 0; i < int(n); i++)
typedef long long li;
using namespace std;
const int INF = 2e9;
li n, h;
bool check(li maxh){
li k = min(h, maxh);
li cnt = maxh * maxh - k * (k - 1) / 2;
return (cnt <= n);
}
li get(li maxh){
li k = min(h, maxh);
li cnt = maxh * maxh - k * (k - 1) / 2;
li len = (2 * maxh - 1) - (k - 1);
n -= cnt;
return len + (n + maxh - 1) / maxh;
}
int main() {
scanf("%lld%lld", &n, &h);
li l = 1, r = INF;
while (l < r - 1){
li m = (l + r) / 2;
if (check(m))
l = m;
else
r = m;
}
printf("%lld\n", check(r) ? get(r) : get(l));
return 0;
}
E. Pencils and Boxes
题目链接:点击打开链接
题目大意:N 个数,要求分成任意堆,要求每一堆只要有K个,同一堆中任意数之间差值不能超过d;
题目思路:用树状数组。排一下序然后从后面开始找,以当前数为最小值看能否成堆,要成堆的话要求i+k,到第一个大于a[i]+d的位置之间有能够成堆的位置。(这里判断的时候树状数组一减看是否大于0就可以了)注意初始化时在n+1的位置加1.
#include <bits/stdc++.h>
using namespace std;
#define forn(i, n) for(int i = 0; i < int(n); i++)
const int N = 500 * 1000 + 13;
int f[N];
void upd(int x){
for (int i = x; i < N; i |= i + 1)
++f[i];
}
int sum(int x){
int res = 0;
for (int i = x; i >= 0; i = (i & (i + 1)) - 1)
res += f[i];
return res;
}
int get(int l, int r){
if (l > r) return 0;
return sum(r) - sum(l - 1);
}
int main(){
int n, k, dif;
scanf("%d%d%d", &n, &k, &dif);
vector<int> a(n);
forn(i, n)
scanf("%d", &a[i]);
sort(a.begin(), a.end());
vector<int> dp(n + 1, 0);
dp[0] = 1;
upd(0);
int l = 0;
forn(i, n){
while (l < i && a[i] - a[l] > dif)
++l;
dp[i + 1] = (get(l, i - k + 1) >= 1);
if (dp[i + 1]) upd(i + 1);
}
puts(dp[n] ? "YES" : "NO");
}
剩下的之后更新。