• #周测 9 —— 高低位交换、Subsequences Summing to Sevens S、积木大赛、跳石头



    很简单的一次周测,先简略记录一下。

    周测网站(给在该团队的人看的)

    高低位交换

    #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;
    
  • 相关阅读:
    mysql 索引
    redis持久化
    redis发布订阅
    django 信号
    paramiko模块
    23种设计模式python实现
    几种浏览器存储数据的方式
    关于传参
    对字符串里的四则运算进行计算2020/10/12
    动手动脑2020/10/9
  • 原文地址:https://www.cnblogs.com/yuanyulin/p/14026727.html
Copyright © 2020-2023  润新知