CodeForces Round #643 A-D 题解,E待补

A. Sequence with Digits

给你一个初始数字a1和计算次数k,每次计算是将ai加上ai这个数的最大的一位数(我们记做maxn)和最小的一位数(我们记做minn)的乘积,得到ai+1。比如a1=487,那a2=487+8*4=519,a3=519+1*9=528,依次类推。

其中a1规模1e18,k规模1e16.

暴力模拟肯定是不要想了

可以发现如果minn=0的话,那从这位数往后的数都不会发生变化了

事实上让minn=0的话,大概只要几十个数就可以做到了

代码:

#include<bits/stdc++.h>
using namespace std;
#define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(x,y) memset(x,y,sizeof(x))
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mp make_pair
#define pb push_back
#define db double
#define inf 0x3f3f3f3f
bool ispow(ll n){return (n&(n-1))==0;}
#define lowbit(x) (x&(-x))
const int mod=1e9+7;
int main()
{
    fast;
    int t;
    cin>>t;
    while(t--){
        ll a,k;
        cin>>a>>k;
        ll ans=a;
        for(ll i=0;i<k-1;i++){
            int minn=10,maxn=0;
            ll temp=ans;
            while(temp){
                int cur=temp%10;
                minn=min(minn,cur);
                maxn=max(maxn,cur);
                temp/=10;
            }
            ans+=minn*maxn;
            if(minn==0) break;
        }
        cout<<ans<<'\n';
    }
    return 0;
}

 

B. Young Explorers

有n个人,第i个人的经验值是ei,经验值为ei的人必须被放到有至少ei个人的小队里面才能行动。

求所能划分的最大组数。

例如 样例2

n=5 e=[2,3,1,2,2],那我们可以让1一组,两个2一组,剩下两个人去不了,总共分了2组。

n规模2e5,ei≤n.

直接记录经验值ei的人的个数,把他们分在一组一定是最优的。

如果经验值ei的人有cnt[ei]个,那么答案总数为cnt[ei] / ei

最后再从小到大扫一遍看看能不能再组一队就好(正好扫到经验值为x的时候出现了x个人,就再组一队)

代码:

#include<bits/stdc++.h>
using namespace std;
#define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(x,y) memset(x,y,sizeof(x))
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mp make_pair
#define pb push_back
#define db double
#define inf 0x3f3f3f3f
bool ispow(ll n){return (n&(n-1))==0;}
#define lowbit(x) (x&(-x))
const int mod=1e9+7;
int e[200005];
int main()
{
    fast;
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        for(int i=0;i<=n;i++) e[i]=0; 
        for(int i=0;i<n;i++) {
            int r;
            cin>>r;
            e[r]++;
        }
        ll ans=0;
        for(int i=1;i<=n;i++) 
        {
            int temp=(e[i]/i);
            ans+=temp;
            e[i]-=(temp*i);
        }
        ll sum=0;
        for(int i=2;i<=n;i++){
            sum+=e[i];
            if(sum>=i){
                sum-=i;
                ans++;
            }
        }
        cout<<ans<<'\n'; 
    }
    return 0;
}

 

D比C简单的多,我们先讲D

 

D. Game With Array

你需要构造一个长度为N的正整数数组,这些数的和为S。

你还需要再确定一个不大于S的正整数K。

如果可以确定出一个K,让这个数组所有的子数组,他们各自的和都不等于K或S-K,就输出这个数组和你选定的K。

否则输出NO。

 

这个题我直接猜结论了。

显然当S ≥ 2N的时候,我们只要选K=1,然后数组为[2,2,2....,S-2(N-1)]即可

 

当S<2N的时候是构造不出来的(H)。下面来证明一下(翻译一下CF的题解):

假设H条件不成立。

让这个数组首尾相连,实际上我们只要找到一个和为K的子数组就可以了(因为首尾相连,找到了K那另一半就是S-K,也满足题意)

对这个数组计算一下前缀和,设计算一遍之后某个数的前缀和为M,然后把前缀和为M+TS(T是任意非负整数,S是数组和)的数给打上标记。

显然,对于我们设的K,M和M+K是不可能同时被标记的

考虑区间[0,2KS),这里面总共有2KN个数被标记了。

把2KS个数按照这样的方式来分:

(0,K), (1,K+1) , ... , (2KSK1,2KS1) 这里面每一对只能有最多1个数被标记

那么就有2KN ≤ KS

我们得到2N ≤ S 这和S<2N矛盾了,所以假设不成立,构造不出来。大概就是这样。

代码:

#include<bits/stdc++.h>
using namespace std;
#define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(x,y) memset(x,y,sizeof(x))
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mp make_pair
#define pb push_back
#define db double
#define inf 0x3f3f3f3f
bool ispow(ll n){return (n&(n-1))==0;}
#define lowbit(x) (x&(-x))
const int mod=1e9+7;
int main()
{
    fast;
    int n,s;
    cin>>n>>s;
    if(s<2*n) cout<<"NO\n";
    else {
        cout<<"YES\n";
        for(int i=0;i<n-1;i++) cout<<2<<' ';
        cout<<s-2*(n-1)<<'\n';
        cout<<1;
    }
    return 0;
}

 

C. Count Triangles

给你四个数A,B,C,D,让你找三个数x,y,z使得:

(1)x,y,z三边构成三角形

(2)≤ ≤ ≤ ≤ ≤ ≤ D

求满足条件的(x,y,z)有多少组。

直接看代码吧,这个题本身没思路,看了qls的讲解就豁然开朗了。

qlstxdy!

#include<bits/stdc++.h>
using namespace std;
#define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(x,y) memset(x,y,sizeof(x))
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mp make_pair
#define pb push_back
#define db double
#define inf 0x3f3f3f3f
bool ispow(ll n){return (n&(n-1))==0;}
#define lowbit(x) (x&(-x))
const int mod=1e9+7;
int main()
{
    fast;
    ll a,b,c,d;
    cin>>a>>b>>c>>d;
    ll ans=0;
    for(ll i=max(a+b,c+1);i<=b+c;i++){//enumerate x+y
        ll l=max(a,i-c),r=min(b,i-b);//number of methods for fixing x(as well as y)
        if(l<=r) ans+=(r-l+1)*(min(i-1,d)-c+1);//number of methods for fixing z.
    }
    cout<<ans<<'\n';
    return 0;
}
//qlstxdy

大概解释一下,因为要构成三角形,那就一定要满足x + y > z

那我们就去枚举x + y的值,x + y的最小值是a + b。

但是要考虑到一个问题,z的最小值是c,所以要保证它们能构成三角形,我们要从max (a + b, c + 1)开始枚举 x + y

枚举的终点自然就是b + c了

然后我们再去枚举x,注意到一点,你枚举x的同时,y值也是被固定下来了,我们只需要看有多少种z可以取到了。

x的区间起点是max (a , i - c),这里的i = x + y,其实就是保证你枚举出来的a可以构成三角形。

区间终点是 min (b, i - b),如果i - b = x + y - b > b的话,就会让y取不到值。

相对应的,要取z的值,只要保证 z ≤ i - 1即可,可能的种数就是 min (i - 1 , d) - c + 1 种

相乘起来就好,qlstxdy。

 

E待补,之后有时间会补上的。

 

posted @ 2020-05-19 16:02  Doomfist  阅读(146)  评论(0)    收藏  举报