Codeforeces #711 DIV2 (A-C) 题解(部分 A-C)

Div2就是刺激啊,人菜瘾大中
目前仅有A-C(人菜).

A.GCD Sum

.题意:给一个数n,定义一个数的gcdsum是 n与其各个位置上数字之和的GCD。比如说gcdsum(762)=gcd(762,7+6+2)=3.现在给你一个数n,找一个大于等于它的数x,令gcdsum(x)>1 。
分析: 模拟即可。记住在分离各个数和的时候要用一个变量保存当前的x.不然就会出现gcd(0,sum)的情况
代码:

#include<bits/stdc++.h>
using namespace std;
long long gcd(long long a,long long b){
	if(b==0) return a;
	return gcd(b,a%b);
}
long long gcdsum(long long x){
	long long sum=0;long long n=x;
	while(x) {
		sum+=x%10;
		x/=10;
		}
	return gcd(n,sum);	
}
int main(){
	int T;cin>>T;
	while(T--){
		long long n;
		cin>>n;
		while(true){
			if(gcdsum(n)>1) {
				cout<<n<<endl;break;
			}
			n++;
		}
	}
return 0;}

B.Box Fitting

题意:给一个长W的盒子,再给出n个wi的矩形高为1.现在要求把矩形全放入盒子,要求高度最小。
思路:该怎么放呢?当然是能放就放。由于要求要多次快速找到某个元素,所以要用二分搜索。而且序列中会有重复,所以要用到multiset。是用lower_bound还是upper_bound呢?答案是后者。因为二分有可能找不到当前的空间(空间还很大),最后迭代器指向末尾,这时候再 it–。那么如果是lower_bound,可能恰好找到当前空间值的wi,这时候再it–,就会使算法错误.故选择后者.
令now=W,意为当前空间.每次二分到一个wi(最大的).就令now减去它,并在multiset中删除该元素,注意删除的是迭代器指向的位置,而不是元素值.不然你就会把对应的元素删光了.当找不到的时候.高度加一,再令now=W.
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
	int T;cin>>T;
	while(T--){
		int n,w;cin>>n>>w;
		multiset<int> s;
		for(int i=0;i<n;i++){
			int x;scanf("%d",&x);
			s.insert(x);
		}
		int now=w;int ans=1;
		while(n){
			multiset<int>::iterator it = s.upper_bound(now);
			 if(it!=s.begin() ){
				it--;
				now-= *it; n--;
				s.erase( it );
			}
			else {
				now=w;ans++;
			}
		}
		cout<<ans<<endl;
	}
return 0;}

C. Planar Reflections

题意:给你n块板子和一个粒子,粒子有一个属性k.当一个粒子透过一个板子时,会有效果:1.该粒子继续以属性k继续向前走。2.产生一个反方向的k-1粒子. 效果2产生的条件是当前粒子k大于等于2.
现在给你n,和k 问你最后算上最初的那个粒子,一共有多少个粒子?
思路:一开始没什么思路,画个图模拟下吧,假设有四个板子
在这里插入图片描述
我们很快注意到:第一次反射的时候,一定产生了n个粒子.我们把四个板子划分的区域定义为1,2,3.
定义dp[i][j]为第i次考虑在j个区域内拥有的新粒子数目.根据上面的说明i=1时,每个区域都只有一个粒子.故dp[1][j]全部是1.(该轮产生的是k-1)
那么我们考虑第二次反射.这一次产生的粒子全是k-2(图上的2).我们怎么考虑的呢,由于这次方向是向右,那么我们从最后一个区域开始考虑.首先第三区域不可能有其他区域对其造成影响.故dp[2][3]=dp[1][3];第二个区域是dp[2][2]=dp[1][2]+dp[2][3];意思是等于上一次自己的粒子+这一次后面的光射进来的粒子.第一个区域同理
再考虑第三次反射。这次的方向是向右,那么要从第一个区域开始考虑.和上面类似,第一个区域无人影响 故dp[3][1]=dp[2][1]; 第二个区域是dp[3][2]=dp[3][1]+dp[2][2];
从上面不难得出转移方程:
当决策数是偶数时:dp[i][j]=(dp[i][j+1]+dp[i-1][j])%mod;代表从右往左考虑
当决策数是奇数时:dp[i][j]=(dp[i][j-1]+dp[i-1][j])%mod 代表从左往右考虑
另外开头的没有其他区域影响:
偶数:if(jn-1) dp[i][j]=dp[i-1][j];
奇数:if(j
1) dp[i][j]=dp[i-1][j];
另外决策只用做k-1次,因为粒子只会衰变k-1次,之后到1就没了。区域也只有n-1个,因为是n个板子,n-1区域嘛
代码:

#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
long long num[1002][1002];
long long dp[1002][1002];
int main(){
	int T;cin>>T;
	while(T--){
		long long ans=1;
		int n,k;cin>>n>>k;
		if(k==1) {
			cout<<1<<endl;continue;
		}
		if(n==1) { cout<<2<<endl;continue; 
		}
		for(int i=1;i<k;i++){
			if(i%2==0) {
				for(int j=n-1;j>=1;j--){
					if(j==n-1) dp[i][j]=dp[i-1][j];
					else {
						dp[i][j]=(dp[i][j+1]+dp[i-1][j])%mod;
					}
					ans=(ans+dp[i][j])%mod;
				}
			}
			else {
				if(i==1) {
					for(int j=1;j<n;j++) dp[1][j]=1;
					ans+=(n);
				}
				else { 
					for(int j=1;j<n;j++) {
						if(j==1) dp[i][j]=dp[i-1][j];
						else dp[i][j]=(dp[i][j-1]+dp[i-1][j])%mod;
						ans=(ans+dp[i][j])%mod;
					}
				}
			}
		}
		cout<<ans<<endl;
	}
return 0;}

剩余题日后再补了,晚上状态太差了,也许是不适应.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

minato_yukina

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值