• Codeforces Round #555 Div. 3


    题目链接:戳我

    完了,最菜就是我了。div.3都写不动QAQ

    A

    按照题意模拟即可,注意判重

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<map>
    #define MAXN 100010
    using namespace std;
    int n;
    vector<int>v;
    map<int,int>m;
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        scanf("%d",&n);
        while(n)
        {
            if(m.count(n)==0)v.push_back(n);
            else break;
            m[n]=1;
            n+=1;
            while(n%10==0) n/=10;
        }
        printf("%d
    ",v.size());
        return 0;
    }
    

    B

    开始看错题了嘤嘤嘤,注意是连续的一段
    直接贪心就行了吧

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<map>
    #define MAXN 300010
    using namespace std;
    int n,kkk;
    int a[MAXN],to[MAXN];
    bool flag=false;
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%1d",&a[i]);
        for(int i=1;i<=9;i++) scanf("%d",&to[i]);
        for(int i=1;i<=n;i++)
        {
            if(to[a[i]]>a[i]&&flag==false) 
            {
                kkk=a[i];
                a[i]=to[a[i]];
                flag=true;
                for(int j=i+1;j<=n;j++)
                {
                    if(to[a[j]]>=a[j]) a[j]=to[a[j]];
                    else break;
                }
                break;
            }
        }
        for(int i=1;i<=n;i++) printf("%d",a[i]);
        return 0;
    }
    

    C1

    因为数都不一样,所以枚举数就行了,看看每次要拿走哪边的qwq

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<map>
    #define MAXN 300010
    using namespace std;
    int n,kkk,maxx=-0x3f3f3f3f,ans;
    int a[MAXN],to[MAXN];
    bool flag=false;
    vector<char>vec;
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        int l=1,r=n;
        for(int i=1;i<=n;i++)
        {
            if(a[l]==i) vec.push_back('L'),l++,ans++;
            else if(a[r]==i) vec.push_back('R'),r--,ans++;
        }
        cout<<ans<<endl;
        for(int i=0;i<vec.size();i++) cout<<vec[i];
        cout<<endl;
        return 0;
    }
    

    C2

    和上一个题唯一不一样的就是这里的值可能不相等。
    注意当两边相等的时候,需要求一下两边各能延展多远,找能取数最多的一边取qwq

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<map>
    #define MAXN 300010
    using namespace std;
    int n,kkk,maxx=1,ans;
    int a[MAXN],to[MAXN];
    bool flag=false;
    vector<char>vec;
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        int l=1,r=n;
        while(maxx<=200000)
        {
            if(l>r||(a[l]<maxx&&a[r]<maxx)) break;
            if(l==r&&a[l]==maxx) 
            {
                if(a[l]==maxx) vec.push_back('L'),l++,ans++;
                else break;
            }
            else if(a[l]==maxx&&a[r]==maxx)
            {
                int cnt1=0,cnt2=0;
                for(int j=l+1;j<=r;j++) 
                {
                    if(a[j]>a[j-1]) cnt1++;
                    else break;
                }
                for(int j=r-1;j>=l;j--)
                {
                    if(a[j]>a[j+1]) cnt2++;
                    else break;
                }
                if(cnt1>cnt2) 
                {
                    maxx=a[l+cnt1]+1;
                    for(int j=0;j<=cnt1;j++)
                        vec.push_back('L'),l++,ans++;
                    
                }
                else 
                {
                    maxx=a[r-cnt2]+1;
                    for(int j=0;j<=cnt2;j++)
                        vec.push_back('R'),r--,ans++;
                    
                }
                continue;
            }
            else if(a[l]==maxx) vec.push_back('L'),l++,ans++;
            else if(a[r]==maxx) vec.push_back('R'),r--,ans++;
            maxx++;
        }
        printf("%d
    ",ans);
        for(int i=0;i<vec.size();i++) printf("%c",vec[i]);
        return 0;
    }
    

    D

    就是因为2的次方增长速度很高,而且第一个数不固定可以任意选取,所以上下界相比而言,上届宽松一些,下届需要更加注意qwq
    我们设当前选取的数为i,如果按照较慢的增长方式,k位后,它们的和为((2i+k-1)*k/2),如果按照较快的增长方式,它们的和为((2^k-1)i)
    那么我们就可以每次尽可能取 以当前数i开始,到m位后 上届大于等于n的最小数。
    所以就是每次选取(a[i]=max(a[i-1]+1,lceil frac{n}{2^{k-i+1}-1} ceil))
    这样子就可以保证每次选取的数是在上届大于等于n的情况下尽可能小的数了。
    之后再判断一下选取的数列合法不合法即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 200010
    using namespace std;
    int n,k,nn;
    int a[MAXN];
    inline bool check()
    {
    	long long cur_ans=a[1];
    	for(int i=2;i<=k;i++)
    	{
    		if(a[i]<=a[i-1]) {return false;}
    		if(a[i]>a[i]*2) {return false;}
    		cur_ans+=a[i];
    	}
    	if(cur_ans!=1ll*nn) return false;
    	return true;
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%d%d",&n,&k);
    	nn=n;
    	for(int i=1;i<=k;i++)
    	{
    		a[i]=max(a[i-1]+1,(int)ceil((double)n/(pow(2.0,k-i+1)-1)));
    		n-=a[i];
    	}
    	if(check()==false) printf("NO
    ");
    	else 
    	{
    		printf("YES
    ");
    		for(int i=1;i<=k;i++) printf("%d ",a[i]);
    	}
    	return 0;
    }
    

    E

    给你两个序列,要求对B进行重排,使得之后((A[i]+B[i])mod n)生成的C序列字典序最小。
    直接贪心地找B序列中有没有(n-A[i])的数,或者离这个数最近的数就行了嘛。
    上一个multiset+lower_bound即可,如果迭代器到了最末尾,让它返回.begin()
    不过需要注意一点.....set的lower_bound需要这样写

    multiset<int>::iterator it=s.lower_bound(k);
    

    而不是

    multiset<int>::iterator it=lower_bound(s.begin(),s.end(),k);
    

    第二种写法会T......谁知道到底是为什么qwq

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #define MAXN 200010
    using namespace std;
    int n;
    int a[MAXN],b[MAXN],c[MAXN];
    multiset<int>s;
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++) scanf("%d",&b[i]),s.insert(b[i]);
        // for(multiset<int>::iterator it=s.begin();it!=s.end();it++) cout<<(*it)<<" "; cout<<endl;
        for(int i=1;i<=n;i++)
        {
            // printf("i=%d
    ",i);
            multiset<int>::iterator cur=s.lower_bound(n-a[i]);
            if(cur==s.end()) cur=s.begin();
            // cout<<(*cur1)<<" "<<(*cur2)<<endl;
            c[i]=((*cur)+a[i])%n;
            s.erase(cur);
        }
        for(int i=1;i<=n;i++) printf("%d ",c[i]);
        return 0;
    }
    

    F

    题意就是给你一堆数,从中间选取尽量多的数,可以把它们放到一个环上,使得相邻两数之差小于等于1.
    显然可以开一个桶计数,然后枚举上届,判断最多能延伸到哪里(每次往下的话,数的个数至少应大于等于2,等于1或者0的时候结束)。然后更新上届为上次延伸到的位置-1即可。

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    #define MAXN 200010
    using namespace std;
    int n,cur,pos,l,r,ans,maxx;
    int a[MAXN],cnt[MAXN],pre[MAXN];
    inline void calc(int x)
    {
    	cur=0;
    	for(int i=x;i>=1;i--)
    	{
    		if(cnt[i]==0) return;
    		if(cnt[i]==1&&i!=x) {cur++;pos=i;return;}
    		cur+=cnt[i];
    		pos=i;
    	}
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) 
    		scanf("%d",&a[i]),cnt[a[i]]++,maxx=max(maxx,a[i]);
    	for(int now=maxx;now>=1;)
    	{
    		calc(now);
    		if(cur>ans) ans=cur,l=pos,r=now,now=pos-1;
    		else now--;
    	}
    	printf("%d
    ",ans);
    	for(int i=l;i<=r;i++) printf("%d ",i),cnt[i]--;
    	for(int i=r;i>=l;i--)
    	{
    		for(int j=1;j<=cnt[i];j++)
    			printf("%d ",i);
    	}
    	return 0;
    }
    

    G

    题意是给你一个矩阵,问能不能通过翻转某些行和某些列,构建一个不下降的矩阵(就是每行顺次连接形成的一个数列不下降)。要求输出是否可以达成目标,如果能,输出行和列的翻转情况。
    因为不下降的矩阵一定是最多一行既有1又有0,然后它前面都是0,它后面都是1
    所以我们可以枚举这个分界点,然后判断是否合法。
    讲道理这个东西应该是(O(n^4))的,但是肯定跑不满。。。而且还很宽松.......所以是O(能过)
    怎么判断是否合法呢?
    因为每个数只有翻转或者不翻转两种情况,所以如果能够构建出来一种方案,那么它的翻转 也是一种合法方案(具体可以手动画图验证)
    所以我们完全可以假设每行的第一个数来决定这一行是否翻转。
    之后每一列的翻转情况就可以确定啦!
    遇到不合法情况直接退出即可。注意每次的行列翻转情况初始化为-1.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define MAXN 210
    using namespace std;
    int n,m;
    int a[MAXN][MAXN],c[MAXN][MAXN],pre[MAXN][MAXN];
    int hang[MAXN],lie[MAXN];
    inline bool solve(int x,int y)
    {
    	for(int i=1;i<=x-1;i++) 
    		for(int j=1;j<=m;j++)
    			c[i][j]=0;
    	for(int j=1;j<y;j++) c[x][j]=0;
    	for(int j=y;j<=m;j++) c[x][j]=1;
    	for(int i=x+1;i<=n;i++) 
    		for(int j=1;j<=m;j++)
    			c[i][j]=1;
    	for(int i=1;i<=n;i++)
    	{
    		hang[i]=a[i][1]^c[i][1];
    		for(int j=1;j<=m;j++)
    		{
    			a[i][j]^=hang[i];
    			if(lie[j]!=-1) 
    			{
    				a[i][j]^=lie[j];
    				if(c[i][j]!=a[i][j]) return false;
    			}
    			else lie[j]=a[i][j]^c[i][j];
    		}
    	}
    	return true;
    }
    inline void print()
    {
    	printf("YES
    ");
    	for(int i=1;i<=n;i++) printf("%d",hang[i]); puts("");
    	for(int i=1;i<=m;i++) printf("%d",lie[i]);
    	exit(0);
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	freopen("ce.out","w",stdout);
    	#endif
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			scanf("%d",&pre[i][j]);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    		{
    			memset(hang,-1,sizeof(hang));
    			memset(lie,-1,sizeof(lie));
    			memcpy(a,pre,sizeof(pre));
    			if(solve(i,j)==true)
    				print();
    		}
    	printf("NO
    ");
    	return 0;
    }
    
  • 相关阅读:
    kmp模板
    2017 ACM/ICPC Asia Regional Shenyang Online transaction transaction transaction
    2017 ACM/ICPC Asia Regional Shenyang Online 12 card card card
    KMP
    最长不下降子序列
    codeforces round 433 D. Jury Meeting
    codeforces round 433 C. Planning 贪心
    hdu 5792 线段树+离散化+思维
    hdu 5792 树状数组+离散化+思维
    hdu 5791 思维dp
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10778950.html
Copyright © 2020-2023  润新知