Codeforces Round #643 (Div. 2) A~E题题解

A. Sequence with Digits

找规律可以发现进行足够多次操作后,一定会出现一个数字含有0,mindigit(x)=0;从那以后,数字就不会再变了;

#include
using namespace std;
#define int long long
#define mem(a) memset(a,0,sizeof(a))
#define lb(x) (x&(-x))
const int inf=0x3f3f3f3f;
const long long mod=1e9+7;
const int maxn=1e5+5;
int dig(int a){
	int num[20];
	int k=0;
	while(a!=0){
		num[k++]=a%10;
		a/=10;
	}
	sort(num,num+k);
	return num[0]*num[k-1];
}
signed main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(0); 
    int t; cin>>t;
	while(t--){
		int a,n;
		cin>>a>>n;
		int ans=a;
		for(int i=1;i<n;i++){
			if(a==a+dig(a)){
				ans=a;
				break;
			}
			a=a+dig(a);
			ans=a;
		}
		cout<<ans<<endl;
	} 
}

B. Young Explorers

题意:将n个人分组,每个人所在的组的人数必须大于等于他的经验值e,可以有人不参与分组,问最多能分多少组。

贪心,先将所有人的e进行升序排序,前面的能分组就分组,这样可以使每组尽可能的小。最后多到的不能组队的人就不参与分组。

#include
using namespace std;
#define int long long
#define mem(a) memset(a,0,sizeof(a))
#define lb(x) (x&(-x))
const int inf=0x3f3f3f3f;
const long long mod=1e9+7;
const int maxn=2e5+5;
int a[maxn];
signed main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(0); 
    int t; cin>>t;
	while(t--){
		int n;cin>>n;
		for(int i=1;i<=n;i++){
			cin>>a[i];
		}
		sort(a+1,a+n+1);
		int ans=0;
		int pos=1;//每组的起始位置
		int cnt=0;
		while(pos<=n){
			cnt=a[pos]-1;
			while(a[cnt+pos]>cnt+1){
			//当前组的最后一个e大于组的大小时
				cnt=a[cnt+pos]-1;
				if(cnt+pos>n) break;
			}
			if(pos+cnt<=n){
				ans++;
			}
			pos=pos+cnt+1;
		}
		cout<<ans<<endl;
	} 
}

C. Count Triangles

给三条边x,y,z的大小范围,(A<=x<=B<=y<=C<=z<=D)
问能组成多少个三角形。
很显然 x<=y<=z;所以要满足 x+y>z;
首先可以将z确定下来,然后根据y的范围(B<=y<=C),求出x(z-C<=x<=z-B)的临界范围,y的每次取值,对应了这个范围内的临界点,x>临界点就可以了。又因为x本身有范围(A<=x<=B),大致可以分成三种情况(见代码吧)。

因为数据范围很大,所以只能一次循环,关于y的取值就不能循环遍历了;
其实手写几组数据就能发现规律:
比如说y取了某个值p,x的临界值对应在q,且q,那么x可以有b-q种情况,这时候如果y=p+1,那么x的情况数就+1,这时候先不考虑特例,假设y的所有取值对应的x临界值都∈(a,b),假设这时候x临界值取值范围为(x,y),那么所有情况的总和就满足
(b-y)+(b-y+1)+…+(b-x)
这不就是等差数列求和吗!
相当于将for(y=a;y<=b;y++){
x=…
ans+=(b-x)
}简化了。
少了一层循环。
最后把几种特殊情况处理一下就ok了。

#include
using namespace std;
#define int long long
#define mem(a) memset(a,0,sizeof(a))
#define lb(x) (x&(-x))
const int inf=0x3f3f3f3f;
const long long mod=1e9+7;
const int maxn=2e5+5;
signed main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(0); 
    int a,b,c,d;
    cin>>a>>b>>c>>d;
    int ans=0;
    for(int i=c;i<=d;i++){
    	if(i-c>=b) break;
    	int l=i-c;
    	int r=i-b;
		if(r<a){
			ans+=(r-l+1)*(b-a+1);
			continue;
		}
		if(l>=b){
			ans+=0;
			continue;
		}
    	if(r>=b){
    		r=b-1;
		}

		if(l<a){
			ans+=min((a-l),(r-l+1))*(b-a+1);
			l=a;
		}
		ans+=((b-r)+(b-l))*(r-l+1)/2;

	}
	cout<<ans<<endl;
}

D. Game With Array

给定n,s;
要构造一个大小为n,和为s的数列a;
问能否构造出一个数组a,其任意子区间的和,都不能与k和s-k(k取1-s的任意值)
很容易想到构造成1,1,1,1,…,s-(n-1) 这样的数组,(直觉,别问为什么
n个数的所有子区间的和∈**[1,…,n-1 , s-(n-1),…,s]**
要满足题意,只要n-1
n-1~s-n+1之间只要有两个空位就可以了

#include
using namespace std;
#define int long long
#define mem(a) memset(a,0,sizeof(a))
#define lb(x) (x&(-x))
const int inf=0x3f3f3f3f;
const long long mod=1e9+7;
const int maxn=1e5+5;

signed main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(0); 
    int n,s;
    cin>>n>>s;
    if(n>s/2){
    	cout<<"NO"<<endl;
    	return 0;
	}
	cout<<"YES"<<endl;
	for(int i=1;i<n;i++){
		cout<<1<<' ';
	}
	cout<<s-n+1<<endl;
	cout<<(s+1)/2<<endl;
}

E. Restorer Distance

给定一个数组,和三种操作a,r,m
因为在操作上 m等价于a+r 所以可以 m = min(m,a+r);
求将所有数变成一样大的消费;
因为h存在最优解,令f(h)表示高度全变成h时的消费。
那么f(h)的函数就类似于二次函数
所以就用三分找到这个h值就可以了。

#include
using namespace std;
#define ll long long 
#define mem(a) memset(a,0,sizeof(a))
#define lb(x) (x&(-x))
const int inf=0x3f3f3f3f;
const int maxn=1e5+5;
ll arr[maxn];    
ll n,a,r,m;
ll f(ll h){
	ll add=0,minus=0;
	for(int i=1;i<=n;i++){
		if(arr[i]<h){
			add+=(h-arr[i]);
		}
		else{
			minus+=(arr[i]-h);
		}
	}
	ll num=min(add,minus)*m;
	if(add>minus){
		num+=(add-minus)*a;
	}
	else{
		num+=(minus-add)*r;
	}
	return num;
}
void solve(){
	if(m>a+r) m=a+r;
	ll l=0,r=inf;
	while(l<r){
		ll midl=l+((r-l)/3);
		ll midr=r-((r-l)/3);
		if(f(midl)<f(midr)){
			r=midr-1;
		} 
		else{
			l=midl+1;
		}
	}
	cout<<f(l)<<endl;;
}
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(0); 
    std::cout.tie(0);
    cin>>n>>a>>r>>m;
    for(int i=1;i<=n;i++){
    	cin>>arr[i];
	}
	solve();
    return 0;
}

你可能感兴趣的:(codeforces)