codeforces思维题专练1

1.Technocup 2021 - Elimination Round 1 A New Technique

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define rep(i,a,n) for(int i=0;i<n;i++)//repeat 默认升序
#define per(i,a,n) for(int i=n;i>=0;i--)//per 对rep的颠倒,默认降序
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
/*
已知每行的相关顺序,
但不知道行的层次,通过列来找到行的层次
因为每一行的第一个元素就决定了该行剩余元素的排列,
所以确定每一行第一个元素的层次也就是,该行在第几行就行了
*/
typedef long long ll;
const int N=510;
int a[N][N],b[N][N];

int main()
{
    IOS;
    int t;cin>>t;
    while(t--)
    {
        int n,m;cin>>n>>m;
        rep(i,0,n)
            rep(j,0,m)
                cin>>a[i][j];
        rep(i,0,m)
            rep(j,0,n)  
                cin>>b[i][j];
        vector<int>ans;
        rep(i,0,n)
        {
            bool flag=false;
            rep(j,0,n)
            {
                rep(k,0,m)
                {
                    if(b[0][i]==a[j][k])
                    {
                        ans.pb(j);
                        flag=1;
                        break;
                    }
                }
                if(flag)
                    break;
            }
        }
        rep(i,0,n)
        {
            rep(j,0,m)
                cout<<a[ans[i]][j]<<" ";
            cout<<endl;
        }
    }
    return 0;
}

2.Codeforces Raif Round 1 (Div. 1 + Div. 2) B - Belted Rooms

算法想假了真的无语

假算法
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define rep(i,a,n) for(int i=0;i<n;i++)//repeat 默认升序
#define per(i,a,n) for(int i=n;i>=0;i--)//per 对rep的颠倒,默认降序
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)

typedef long long ll;
const int N=3e5+10;
int id[N],od[N];
/*
假的算法,出度入度并不直接A能否返回A
*/
int main()
{
    IOS;
    int t;cin>>t;
    while(t--)
    {
        memset(id,0,sizeof id);
        memset(od,0,sizeof od);
        int n;char s[N];
        int cnta=0;
        cin>>n>>s+1;
        //第i个符号会影响第i和i+1个点. 
        // for(int i=1;i<n;i++)
        //     cout<<s[i]<<" ";
        // cout<<endl;
        for(int i=1;i<n;i++)
        {
            if(s[i]=='-')
            {
                cnta++;
                id[(i+1)]++,id[i]++;
                od[(i+1)]++,od[i]++;
            }
            else if(s[i]=='>')
            {
                id[(i+1)]++,od[i]++;
            }
            else if(s[i]=='<')
            {
                id[i]++,od[(i+1)]++;
            }
        }
        if(s[n]=='-')
        {
            cnta++;
            id[1]++,id[n]++;
            od[1]++,od[n]++;
        }
        else if(s[n]=='>')
        {
            id[1]++,od[n]++;
        }
        else
        {
            id[n]++,od[1]++;
        }
        
        int cnt=0;
        bool flag=true;
        for(int i=1;i<=n;i++)
        {
            // cout<<id[i]<<" "<<od[i]<<endl;
            if(!od[i]||!id[i])
            {
                flag=false;
            }
            if(id[i]&&od[i])
                cnt++;
        }
        if(cnta)
            cout<<cnt<<endl;
        else
        {
            if(flag==false)
                cout<<0<<endl;
            else
                cout<<cnt<<endl;
        }
    }
    
    return 0;
}
正解
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define rep(i,a,n) for(int i=0;i<n;i++)//repeat 默认升序
#define per(i,a,n) for(int i=n;i>=0;i--)//per 对rep的颠倒,默认降序
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)

int main(){
    IOS;
    int t;cin>>t;
    while(t--){
        int n;cin>>n;
        string s;cin>>s;
        bool hasCw=false,hasAcw=false;
        for(int i=0;i<n;i++){
            if(s[i]=='<')
                hasAcw=true;
            if(s[i]=='>')
                hasCw=true;
        }
        if(hasCw&&hasAcw){
            int ans=0;
            s+=s[0];//好巧妙,运用了string的特点,使得循环变成的顺序
            for(int i=0;i<n;i++){
                if(s[i]=='-'||s[i+1]=='-')
                    ans++;
            }
            cout<<ans<<endl;
        }
        else{
            cout<<n<<endl;
        }
    }
    
    return 0;
}

3.Educational Codeforces Round 96 (Rated for Div. 2) C. Numbers on Whiteboard

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define rep(i,a,n) for(int i=0;i<n;i++)//repeat 默认升序
#define per(i,a,n) for(int i=n;i>=0;i--)//per 对rep的颠倒,默认降序
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)

typedef long long ll;
const int N=3e5+10;

int main()
{
    IOS;
    int t;cin>>t;
    while(t--)
    {
        int n;cin>>n;
        cout<<2<<endl;
        if(n==2)
            cout<<2<<" "<<1<<endl;
        else
        {
            cout<<n-1<<" "<<n<<endl;
            for(int i=n-2;i>=1;i--)
                cout<<i<<" "<<i+2<<endl;
        }
    }
    
    return 0;
}

4.Codeforces Round #675 (Div. 2) B. Nice Matrix

\( 观察到,若让矩形是回文的必有a[i][j]=a[n-i+1][j]=a[i][m-j+1],(数组下标为a[1\sim n,1\sim m])\\ a[i][j]=a[n-i-1][j]=a[i][m-j-1],(数组下标为a[0\sim n-1,0\sim m-1])\\ \)

想假的算法
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define rep(i,a,n) for(int i=0;i<n;i++)//repeat 默认升序
#define per(i,a,n) for(int i=n;i>=0;i--)//per 对rep的颠倒,默认降序
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)

typedef long long ll;
const int N=110;
int a[N][N];
int main()
{
    IOS;
    int t;cin>>t;
    while(t--)
    {
        int sum=0;
        memset(a,0,sizeof a);
        int n,m;cin>>n>>m;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                cin>>a[i][j];
                sum+=a[i][j];
            }
        }
        // cout<<sum<<endl;
        sum=sum/m/n;
        // cout<<sum<<endl;
        ll cnt=0;
        rep(i,a,n)
        {
            rep(j,a,m)
            {
                if(sum>=a[i][j])
                    cnt+=sum-a[i][j];
                else
                    cnt+=a[i][j]-sum;
            }
        }
        cout<<cnt<<endl;
    }
    return 0;
}
/*
4 2

4 2
2 4
4 2
2 4

10+26+48==84/12==7
6+5+4+3
+2+1+1+2+3+4+11==21+10+11==42
对于
3*4

a[2][2]=a[2][2]=a[1][3]=a[2][3]
*/
正解
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define rep(i,a,n) for(int i=0;i<n;i++)//repeat 默认升序
#define per(i,a,n) for(int i=n;i>=0;i--)//per 对rep的颠倒,默认降序
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)

typedef long long ll;
const int N=110;
int a[N][N];
int main()
{
    IOS;
    int t;cin>>t;
    while(t--)
    {
        int n,m;cin>>n>>m;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                cin>>a[i][j];
            }
        }
        ll cnt=0;
        rep(i,a,n)
        {
            rep(j,a,m)
            {
                vector<int>ans;

                ans.pb(a[i][j]);
                ans.pb(a[n-i-1][j]);
                ans.pb(a[i][m-j-1]);
                sort(ans.begin(),ans.end());
                // for(auto x:ans)
                //     cout<<x<<" ";
                // cout<<endl;
                cnt+=ans[1]-ans[0];
                cnt+=ans[2]-ans[1];
                a[i][j]=a[n-i-1][j]=a[i][m-j-1]=ans[1];
            }
        }
        cout<<cnt<<endl;
    }
    
    return 0;
}

6.Codeforces Round #670 (Div. 2) B. Maximum Product

\( 一开始这题完全没有思路,一开始认为是从原数组中不打乱顺序求出5个数乘积的最大值(被迷惑了,大雾)\\ 后来看了人家的题解,发现虽然这五个数是有顺序的,但题目没说不能乱序啊!拿出5个数来,数字的下标当然不同了\\ 分析符号,首先降序排序 1.如果全正或全负,前五个数的乘积最大,如果升序排序则要多写一个乘积\\ 2.当有正有负时,负数的个数必须是0,2,4,5,其中0,5已经被讨论过了 所以再取2和4个负数,再乘积,最后比较3个乘积的最大值输出即可 \)

法一

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
#define rep(i,a,n) for(int i=0;i<n;i++)//repeat 默认升序
#define per(i,a,n) for(int i=n;i>=0;i--)//per 对rep的颠倒,默认降序
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)

typedef long long ll;
const int N=111000;
int t;
ll n;
ll a[N];
bool cmp(ll a,ll b)
{
    return a>b;
}
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>t;
    while(t--){
    	cin>>n;
    	for(int i=1;i<=n;++i){
    		cin>>a[i];
    	}
    	sort(a+1,a+1+n,cmp);
    	ll cnt1=a[1]*a[2]*a[3]*a[4]*a[5];
    	ll cnt2=a[1]*a[2]*a[3]*a[n]*a[n-1];
    	ll cnt3=a[1]*a[n]*a[n-1]*a[n-2]*a[n-3];
    	cout<<max(cnt1,max(cnt2,cnt3))<<endl;
    }
 
    return 0;
}

法二

#include<bits/stdc++.h>
using namespace std;
long long ans,a[100005];
int main() {
	int t;
	scanf("%d",&t);
	while(t--){
		int n;
		long long mx=-1e9;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)scanf("%lld",&a[i]),mx=max(mx,a[i]);
		sort(a+1,a+n+1,[](long long x,long long y){return abs(x)>abs(y);});
		if(mx<0){
		    cout<<a[n]*a[n-1]*a[n-2]*a[n-3]*a[n-4]<<'\n';
		    continue;
		}
		ans=a[1]*a[2]*a[3]*a[4]*a[5];
		//这是绝对值最大的五个数的乘积
		/*
		-3 -2 -1 1 2 3 4 5
		5 4 3 -3 2 -2 1 -1
		*/
		//把前五个绝对值最大的数中的某一个数替换成后边n-5中的某一个数
		for(int i=6;i<=n;i++)
		{
		    for(int j=1;j<=5;j++)
		    {
		        long long tmp=a[i];//想要更换的那个数
		        for(int k=1;k<=5;k++){
		            if(k!=j)tmp*=a[k];
		        }
		        ans=max(ans,tmp);
		    }
		}
		printf("%lld\n",ans);
	}
    return 0;
}

7.CodeForces - 1405 B Array Cancellation

\( 法一.\\ O(N)跑一遍前缀和,如果前缀和小于0,代表必须付出的代价,累计abs(代价),前缀和清空\\ 最后输出代价。\\ 法二.\\ 定义后缀和c[i]=a[i]+a[i+1]+...+a[n]\\ 最后有a[0]=a[1]=a[2]=...=a[n]=0,所以有c[n]=c[n-1]=...=c[1]=0; 因为a[i]=c[i]-c[i+1],a[j]=c[j]-c[j+1],当i<j时,尽量让a[i]--,a[j]++\\ 就有c[i+1]++,c[j]++;\\ 即c[i+1]...c[j]这段连续的数组越大越好.处理后缀和数组,输出最大后缀和就是ans. \)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+5;
ll a[maxn];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        for(int i=0;i<n;i++)
            cin>>a[i];
        ll ans=0,sum=0;
        for(int i=0;i<n;i++)
        {
            ans+=a[i];
            if(ans<0)
                sum+=-ans,ans=0;
        }
        cout<<sum<<endl;
    }
    return 0;
}
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
#define rep(i,a,n) for(int i=0;i<n;i++)
#define per(i,a,n) for(int i=n;i>=0;i--)
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)

typedef long long ll;
const int N=111000;
ll a[N];
ll sum;
int main()
{
	IOS;
	int t;cin>>t;
	while(t--)
	{
	    int n;cin>>n;
	    ll ans=-1e6;
	    for(int i=n;i>=1;i--)
	        cin>>a[i];
	    for(int i=1;i<=n;i++)
	    {
	        sum+=a[i];
	        ans=max(ans,sum);
	    }
	    cout<<ans<<endl;
	}
	return 0;
}

8.CodeForces - 1392 C Omkar and Waterslide

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
#define rep(i,a,n) for(int i=0;i<n;i++)
#define per(i,a,n) for(int i=n;i>=0;i--)
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)

typedef long long ll;
/*
思路:(假思路)
假了,wok,最烦这种想一会发现对不上题。
如果数组最大最小值相等输出0
否则使用双指针遍历原始数组
找到区间[i,j],该区间所有元素的最大值一定小于max,求出区间[i,j]中最小的元素a,
ans=max-a

别人的思路
题意:目的:数组不递减,可以让连续的一段区间[l,r],上,各个元素自增1
10 5 3 7 2 10
1.让 5 3 7 2 变成10;
2.让 5 3 变成7 2变成7;
3.让 3变成5 
上述操作可以写成
if(a[i]>a[i+1])
sum+=a[i]-a[i+1];
输出sum即为ans
*/
const int N=2e5+10;
int a[N];
int main()
{
	IOS;
	int t;cin>>t;
	while(t--)
	{
	    int n;cin>>n;
	    for(int i=1;i<=n;i++)
	        cin>>a[i];
	    ll sum=0;
	    for(int i=1;i<n;i++)
	    {
	        if(a[i]>a[i+1])
	            sum+=a[i]-a[i+1];
	    }
	    cout<<sum<<endl;
	}
	return 0;
}
posted @ 2020-11-17 21:36  30天CF上蓝!!!  阅读(310)  评论(0编辑  收藏  举报