很基础的题目,我们只需要按照循序将他们放到1、3、5、7....... 或者 2、4、6、8.......就可以因为棋子不可以进行跳跃,只能一个一个地移动,并且只能顺序移动,所以只用这两种情况,开始错了,因为没有排序
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <algorithm> #define INF 0x3f3f3f3f #define ll long long using namespace std; const int MAXN = 150; int a[MAXN]; int main() { int n; scanf("%d",&n); for(int i =0 ;i < n/2;i ++) scanf("%d",&a[i]); sort(a,a+n/2); int ans = 0,ans2 = 0,tmp = 1,tmp2 = 2; for(int i = 0;i < n/2;i ++) { ans += abs(tmp - a[i]); tmp += 2; } for(int i = 0;i < n/2;i ++) { ans2 += abs(tmp2 - a[i]); tmp2 += 2; } printf("%d\n",min(ans,ans2)); }
题目意思可以转换为:寻找某一行满足:其中包含1的位置,别的行中在这个位置上也存在是1的情况,这个题也后来被Hacked了,开始不想直接遍历,想找个更快的方法,然后思路就错了,当时思路是:从开始向下寻找,如果某一行中存在的1,前面前几行全部有了,那么也就表示这一行可以去掉。但是后来被hacked了想:如果当前行的后面存在了,但是前面没有满足条件,那么不就错了.....
不得不又循环了一次
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <algorithm> #define INF 0x3f3f3f3f #define ll long long using namespace std; const int MAXN = 2100; int vis[MAXN]; char s[MAXN][MAXN]; int n,m; int main() { memset(vis,0,sizeof(vis)); scanf("%d%d",&n,&m); for(int i = 0;i < n;i ++) { scanf("%s",s[i]); for(int j = 0;j < m;j ++) vis[j] += s[i][j] - '0'; } bool flag = false; for(int i = 0;i < n;i ++) { flag = false; for(int j = 0;j < m ;j ++) { if(s[i][j] == '1' && vis[j] == 1) { flag = true; break; } } if(!flag) break; } if(!flag) printf("YES\n"); else printf("NO\n"); }
题目意思是:一共n个木桶,每个木桶由k个木棍组成,给出n*k个木棍,那么木桶最大的盛水量就是最短的木棍决定的,要求木桶盛水量差不能大于l,问最大的总盛水量为多少?
当时想到了很简单的贪心,先选出长度和最短的差距在l范围之内的木棒,然后选取最长的木棒优先,但是写的太麻烦了,自己都把自己绕进去了,最后也没写出来,今天整理了一下思路,发现只要后面的木棒树大于等于k-1个,我们就可以拿出这k-1个然后选择一个前面的木棒中最长的组成一个木桶,依次向前推,就可以了.....
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <algorithm> #define INF 0x3f3f3f3f #define ll long long using namespace std; const int MAXN = 1e5+1000; int n,k,l; ll a[MAXN]; int main() { while(~scanf("%d%d%d",&n,&k,&l)) { int num = n * k; for(int i = 1;i <= num;i ++) scanf("%I64d",&a[i]); sort(a+1,a+1+num); int high = upper_bound(a+1,a+1+num,a[1] + l) - a; if(high - 1 < n) printf("0\n"); else { ll ans = 0; int x = num - high + 1,pos = high - 1; for(int i = pos;i >= 1;i --) { if(x >= k-1) { ans += a[i]; x -= k-1; } else x++; } printf("%I64d\n",ans); } } }
题目意思为:有n桶沙子,最左边高h,我们从坐标1开始向后安排沙子高度,相邻高度差不能超过1,最后一个高度必为1,并且第一个高度要小于等于h,求解最少需要安排多少堆可以安排完这个n数量?
思路参考博客:https://www.cnblogs.com/tobyw/p/9070846.html
这里我们可以枚举安排沙子的长度k,并且求解在长度k的条件下,我们可以使用的最大沙子数量,如果小于给出的数量,则在范围后半段计算,相反大于给出的数量,则在范围前半段进行计算
我们怎么计算长度k以及左边栅栏高度确定的请款下,能使用的最大沙子数量呢?
我们所能达到的最大使用量安排图一定是上面这样的,一种情况是:k>h ,另一种为k <= h
当k <= h时,使用的数量很好计算:(1+k)*k/2
当k > h 时,我们将图分成两部分:
因为红色部分之外我们要进行分来讨论,当白色部分长度为奇数时,白色部分计算方式为一种,当问偶数时计算方式为一种,这里不再进行展开了,程序中写的非常清楚
但是这样我们还是会错误,因为最大数据为1e18的时候,我们在计算使用数量的时候会查出long long的范围,那么我们就要缩小一下开始二分的两端范围:
最大数值:满足下面情情况:最大数值为:2*sqrt(n) + 1 (假设下面面积为n,那么这个数值就是对应的坐标长度)
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <cmath> #include <algorithm> #define INF 0x3f3f3f3f #define ll long long using namespace std; const int MAXN = 5*1e5+1000; ll n,H; bool Judge(ll k)//二分长度,求解长度的最大面积,面积大于,返回true,否则返回false { ll area = 0; if(k <= H) area = (1+k)*k/2; else { area += (H - 1)*H/2; ll x = ceil(double(k - H - 1)/2) + H; //可以到达的最大高度 k -= H - 1; if(k & 1) //奇数 area += x + (x - H) * (H + x - 1); else area += (x - H + 1) * (x + H); } //cout<<k<<" "<<area<<endl; return area >= n; } ll Solve() { ll l = 1,r = 2*sqrt(n)+1;//这里一定要注意其实范围的选取,否则后面范围很容易超出ll范围 while(l <= r) { ll mid = (l+r) >>1; if(Judge(mid)) r = mid - 1; else l = mid + 1; } return l; } int main() { cin>>n>>H; cout<<Solve()<<endl; return 0; }
掉分之旅又要开始了.....这次看来又要掉分了,记录下当前的分数:1256