很简单的一次周测,先简略记录一下。
周测网站(给在该团队的人看的)
高低位交换
#include<bits/stdc++.h>
using namespace std;
int s[33];
int main(){
long long x;
cin >> x;
for(int i = 32; i >= 1; i --){
//如果当前最低位上有数
if(x % 2 == 1) s[i] = 1;//对应位置为 1
x >>= 1;//处理完之后就去掉最后一位
}
for(int i = 17; i <= 32; i ++){
x <<= 1;
x |= s[i];
}
for(int i = 1; i <= 16; i ++){
x <<= 1;
x |= s[i];
}
cout << x;
return 0;
}
/*
//首先来分析一下,这道题很有意思;
//给定一个数 x,
//然后 按照二进制码, 将它 的前十六位 与 后十六位 交换;
//具体操作:
//一、用另一个数 a 来 复制这个数 x;
//二、将 a往后移16位:
//a >> 16;
//三、同样的, 用一个数 b 来复制 x , 并将其 往前移16位;
//最后将 a、b相加;
//不出意料失败了;
//不过没关系,我们分开来做
//首先最最重要的就是后十六位, 因为我们不知道往前移会发生什么东西;
//所以我们先将这个数的二进制位拆分:
for(int i = 1; i <= 32; i ++){
//如果当前最低位上有数
if(x % 2) s[i] = 1;//对应位置为 1
x >> 1;//处理完之后就去掉最后一位
}
//现在我们处理完了,下一步就是重新组合这个数了
//第一步,我们将第17到32位的数加上,也就是先把 y 往右移一位,然后 |1(或上1)
//第二步,我们将第1到16位上的数进行操作 ~ 完成 ~
//后来发现 x 取完之后就空了,于是计划好的 y 就变成 x 了;
//为了防止某些 边界问题 我保险起见用long long 吧
*/
跳石头
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
ll a[N];
int main(){
ll L;
int n, m;
// scanf("%d%d%d", &L, &n, &m);//最大距离, 石头数, 最大移走数
cin >> L >> n >> m;
for(int i = 1; i <= n; i ++){
ll d;
// scanf("%d", &d);
cin >> d;
a[i] = d;
}
if(n == 0){
cout << L;
return 0;
}
//二分答案:使得选手们在比赛过程中的最短跳跃距离尽可能长 我们就枚举 这个——最短的跳跃距离。
ll l = 0, r = L + 1, mid;
int k = 1;
//现在第一块没有被移走的石头就是1了
//k代表的是 还未被移走的第一块 石头, 于是我们每移走一块石头,k都要向后移一位。
int cnt;
a[n + 1] = L;
ll res = -1;
while(l <= r){
cnt = 0, k = 1;//每一轮都要刷新一次哦。
mid = (l + r) / 2;
for(int i = 0; i <= n;){//为什么从第0块石头开始枚举呢?因为第0块石头就是起点
ll d = a[k] - a[i]; //d是当前节点到 k 的距离啦
while(mid > d && k <= n){//如果 d 小于我们要求的最小距离,那么就把 第k块石头 移开
cnt ++;//移开的数目++
k ++;//k往后移
d = a[k] - a[i]; //更新 d 的值
}
//现在这一轮之后,从i开始后面符合距离的石头全部移开了,那么下一步我们就要跳到 k这个位置上了
i = k;
k ++;
}
if(cnt <= m){//合法 ,增加距离
res = max(res, mid);
l = mid + 1;
}
else {//不合法 ,缩短距离
r = mid - 1;
}
}
cout << res<< endl;
// printf("%lf MB", (double)sizeof(a) / (1024 * 1024));
return 0;
}
//什么意思呢?就是说,移走之后, 所有石头之间的距离大于等于这个数 。
//那哪些石头会被移走呢?
//从第i块石头到第j块石头的距离 d 如果 小于 我们所枚举的这个距离 mid,那就移走第j块石头;
//那移走会怎么样? cnt ++
//不移走呢?那就把指针 k 移动到第j块石头上
//如果 结果 比 能移开的石头数多, 那我们尝试缩小这个距离;注意:这是不合法的,所以它的答案我们一律不会采纳。
//如果 结果 比 能移开的石头数少, 那就扩大这个距离;注意:此时它的答案是合法的,所以我们会采纳尽量大的数;
//如果没有石头可以移动呢???!!!
积木大赛
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
typedef long long ll;
int a[N], tail;//从1开始 , 所以尾巴在0这里,代表没有数!
//优先队列
ll cnt;
int main(){
int n, x;
cin >> n;
for(int i = 1; i <= n; i ++){
scanf("%d", &x);//当前的数,但不急着加入
//先判断它与最后一个元素的关系
//首先是大于等于最后一个元素
//那就直接加入就好
if(x >= a[tail]){ a[++tail] = x; }
//然后是小于最后一个元素
else{
//首先将操作数加上
cnt += (ll)(a[tail] - x);
//然后将所有前面比他高的全部干掉吧 !(嫉妒心:MAX )
//移动尾巴就好啦,不用枚举;注意不用超出数组范围
while(tail > 0 && a[tail] > x) tail --;
//然后就可以入队啦
a[++tail] = x;
}
}
//最后的处理
cnt += (ll)a[tail];
cout << cnt;
return 0;
}
/*
//好形象啊
//似乎可以用优先队列来做
//不过又有所不同,毕竟它是每次只能建一层楼高……
//对了!!!如果本次输入导致那一层的延续断掉了,那么cnt++不久好了吗?
//分两种情况,
//第一种: 这次输入的是比优先队列最后一个元素大的
//直接加入吧没什么大不了的
//第二种: 这次输入的是比优先队列最后一个元素小的
//这就有意思了,我们要将 最后一个元素 到 当前元素中间的所有楼层都 “建好”。
//也就是操作数为 两者之差;
cnt += (a[tail] - x);
//第三种,最后的处理;
//最后剩下的怎么办??
//最简单了,直接加上最后一个元素就可以了!!!
cnt += a[tail];
//cnt会超出int 的范围吗??
//cnt最大会是多少呢??
//假设有一个很邪恶的数据,它每次都卡范围,按照10000、1、10000、1……的顺序来建房子
//这样的组合最多有50000个,每一组侧次数是9999(算它10000)
//那么我们的cnt最大就是 500000000 , 9位数啦!!!
//所以以防万一,我们开long long !
*/
Subsequences Summing to Sevens S
//Subsequences Summing to Sevens S
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int a[N], s[N], b[7];
//b是那个数第一次出现在的位置
int res = -1;
int main(){
memset(b, -1, sizeof b);
int n;
cin >> n;
for(int i = 1; i <= n; i ++){
scanf("%d", &a[i]);
a[i] %= 7;
s[i] = (a[i] + s[i - 1]) % 7;
if(b[a[i]] == -1) b[a[i]] = i;//没有出现过就更新位置
}
//前缀和 %7
for(int i = 1; i <= n; i ++)
if(s[i] == 0) res = max(res, i);
else if(b[s[i]] != -1 && b[s[i]] < i)//如果这个数存在
res = max(res, i - b[s[i]]);
cout << res;
return 0;
}
//前缀和做法,
//首先开一个数组a,将所有输入的数取模
//再开一个前缀和数组s,将所有前缀和对7取模
//再开一个数组b,用来记录0~6第一次分别出现的位置
//然后遍历前缀和数组,如果上面对7取模的结果存在,那么就用当前位置i减去s[i]第一次出现的位置就可以了。
//或者已经为0,也就是前缀和本身是7的倍数,那此时长度就是i;
//比较最大的结果res;