zoukankan      html  css  js  c++  java
  • Codeforces Round #481 (Div. 3) 解题报告

    A - Remove Duplicates

    题目大意:

    现在有一个长度为n的一串数字,要将其中相同的数字删掉。删除的规则:如果数字相同时保留最右边的那一个。输出删除之后的数字串

    大致思路:

    暴力模拟情况就好···虽然我感觉我写的非常复杂,应该有更简单的写法。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1010;
    int a[55];
    struct Node{
    	int pos,id;
    	Node(){pos=0;id=0;}
    }pos[maxn];
    bool visit[maxn];
    bool cmp(Node a,Node b)
    {
    	return a.pos<b.pos;
    }
    int main()
    {
    	ios::sync_with_stdio(false);
    	memset(visit,false,sizeof(visit));
    	int n,cnt=0;
    	cin>>n;
    	for(int i=1;i<=n;++i){
    		cin>>a[i];
    		if(pos[a[i]].pos==0)
    			cnt++; //数有多少个数字
    		pos[a[i]].pos = i;//记录某一个数出现的最后位置
    		pos[a[i]].id = a[i];
    	}
    	vector<Node> q;
    	cout<<cnt<<endl;
    	for(int i=1;i<=n;++i){//把结果放到数组里就可以了
    		if(visit[a[i]]==false){
    			q.push_back(pos[a[i]]);
    			//cout<<pos[a[i]].pos<<" "<<pos[a[i]].id<<endl;
    			visit[a[i]]=true;
    		}
    	}
    	sort(q.begin(),q.end(),cmp);
    	for(int i=0;i<cnt;++i)
    		cout<<q[i].id<<" ";
    	cout<<endl;
    	return 0;
    }
    

    B - File Name

    题目大意:

    现在有一个长度为n的字符串,现在想让字符串中不存在连续的三个x字符。问需要删除多少个字符。

    大致思路:

    也是暴力模拟就好,循环里一个计数器,看连续的x的个数

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    char str[110];
    int main()
    {
    	int n,ans=0,cnt=0;
    	cin>>n>>str;
    	for(int i=0;i<n;++i){
    		//cout<<i<<" "<<cnt<<" "<<ans<<endl;
    		if(str[i]!='x') cnt=0;
    		else cnt++;
    		if(cnt==3){
    			ans++;
    			cnt--;
    			
    		}
    	}
    	//cout<<str<<endl;
    	cout<<ans<<endl;
    	return 0;
    }
    

    C - Letters

    题目大意:

    题目背景比较复杂,现在简化一下:

    (n) 个房间,按 $ 1...n$ 进行编号, 每个房间里有 (a_i) 个格子。

    (m) 个询问,每个询问给出一个数字,代表着我现在要找的是第 (x) 个格子

    这个 (x) 是对于全局的。比如我现在第一个房间里有10个,第二个房间里有10个。那么第二个房间里的格子的序号就是从 (11...20)

    要求对于每一个询问,输出这个格子所在的房间号和这个格子相对于这个房间的序号。

    解题思路:

    对于 (a_i) 求一个前缀和。对于每一个询问在前缀和里面进行二分,答案就很显然的出来了。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=2e5+7;
    ll a[maxn],b[maxn],pre[maxn]={0};
    int main()
    {
    	ios::sync_with_stdio(false);
    	int n,m;
    	cin>>n>>m;
    	for(int i=1;i<=n;++i)
    		cin>>a[i];
    	for(int i=1;i<=m;++i)
    		cin>>b[i];
    	for(int i=1;i<=n;++i)
    		pre[i] = a[i]+pre[i-1];
    	for(int i=1;i<=m;++i){
    		int pos = lower_bound(pre+1,pre+1+n,b[i]) -(pre+1);
    		cout<<pos+1<<" "<<b[i] - pre[pos]<<endl;
    	}
    	
    	return 0;
    }
    

    吐槽一下:这个题给了4s,是想让 (O(nm)) 的暴力也能过吗···


    D - Almost Arithmetic Progression

    题目大意:

    有一个长度为 (n) 的数字序列,你可以对每一个数字进行一次 (+1) 或者 (-1) 的操作。

    使得这个序列变成一个等差序列。现在求最小的操作次数,如果不能变成等差序列,就输出 (-1)

    解题思路:

    对于整个序列枚举公差就好了。

    先将数列的最大值和最小值得到,假设为 (maxx)(minl)

    现在设公差为 (d) ,序列长度为 (n)

    那么可以很显然的得到:

    (d imes (n-1) = (maxx-minl-2) ldots (maxx-minl+2))

    然后这个题有一个 (trick) ,就是公差可以是负数,所以就需要扫两次。正向一个,反向一次

    这个算法的最坏情况下就是 (2 imes 4 imes 3 imes n) 次循环,也就是 (2e6)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int INF =1<<30;
    const int maxn=1e5+7;
    int a[maxn];
    int main()
    {
        //freopen("in.txt","r",stdin);
    	ios::sync_with_stdio(false);
    	int n;
    	cin>>n;
    	for(int i=1;i<=n;++i)
            cin>>a[i];
        if(n<=2){
            cout<<0<<endl;
            return 0;
        }
    
    	int maxx = -INF,minl = INF,ans=1<<30;
    	for(int i=1;i<=n;++i)
            maxx = max(maxx,a[i]),minl = min(minl,a[i]);
    
    	//cout<<maxx<<" "<<minl<<endl;
    	int d;
    	bool flag=false;
    	for(int i=maxx-minl-2;i<=maxx-minl+2;++i){ //正向
    		if(i%(n-1)==0){
    			d=i/(n-1); //枚举公差
    			ll now;
    			//cout<<d<<endl;
    			for(int i=-1;i<=1;++i){
    				int cnt=0,x;
    				now = a[1] +i;
    				for(int i=1;i<=n;++i){
    					x=abs(now-a[i]);
    					if(x>1){now=0;break;}
    					if(x!=0) cnt++;
    					now+= d;
    				}
    				if(now){
                        //cout<<d<<" "<<a[1]+i<<endl;
    					ans =min(ans,cnt);
    					flag=true;
    				}
    	 		}
    		}
    	}
    	if(!flag)
    	for(int i=minl-maxx-2;i<=minl-maxx+2;++i){ //反向
    		if(i%(n-1)==0){
    			d=i/(n-1);
    			ll now;
    			//cout<<d<<endl;
    			for(int i=-1;i<=1;++i){
    				int cnt=0,x;
    				now = a[1] +i;
    				for(int i=1;i<=n;++i){
    					x=abs(now-a[i]);
    					if(x>1){now=0;break;}
    					if(x!=0) cnt++;
    					now+= d;
    				}
    				if(now){
                        //cout<<d<<" "<<a[1]+i<<endl;
    					ans =min(ans,cnt);
    					flag=true;
    				}
    	 		}
    		}
    	}
    	if(flag)
    		cout<<ans<<endl;
    	else
    		cout<<-1<<endl;
    	return 0;
    }
    

    E - Bus Video System

    题目大意:

    有一辆公交车,现在知道连续 (n) 个站的上下人数之和,还有车的容量。

    问这个车在开到这n个站之前的人数可能情况有多少种。

    解题思路:

    将情况简单模拟一下,就可以知道有以下的规律:

    在这 (n) 个站的过程中,出现的最大数大于0,说明之前肯定有至少有这么多的空位。

    若出现的最小数<0,则说明之前肯定至少有这么多人已经在车上了。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int INF =1<<30;
    int main()
    {
        int n,w,num;
        while(cin>>n>>w)
        {
            int now=0,maxx=-INF,minl=INF;
            for(int i=0;i<n;++i){
                cin>>num;
                now+=num;
                maxx = max(maxx,now);
                minl = min(minl,now);
            }
            int ans = w+1;
            if(minl!=-INF && minl<0)
                ans+=(minl);
            if(maxx!=INF && maxx >0)
                ans-=(maxx);
            if(ans<0)
                ans=0;
            //cout<<maxx<<" "<<minl<<endl;
            cout<<ans<<endl;
        }
        return 0;
    }
    

    F - Mentors

    题目大意:

    (n) 个人,每一个人有一个技能值 (r)(m) 对人之间有争吵。现在定义一个关系:教师

    (forall a,b in n , r_a > r_b)(a)(b) 之间没有争吵,那么 (a) 可以做 (b) 的教师

    现在问对于每一个人,能做多少个人的教师?

    解题思路:

    给每一个人建一个set。

    意义为:(forall x in set[a] , r_a > r_x)

    也就是说 (a) 可以做 (x) 的教师

    然后把每个人的信息按技能值排序。到时候看排序后的位置减去 (set) 的大小就可以了。

    但这里还涉及到一个问题:存在多个人技能值相同 。

    也就是说不能直接按照排序后的位置直接当成答案,还需要去找到第一个比自己技能值小的人的位置。

    最简单暴力的方法就是每一次循环暴力找

    如我第一次提交的代码:

    for(int i=n;i>=1;--i){
            int j=i-1;
            while(pro[i].r<=pro[j].r) //暴力寻找第一个比i小的位置
                j--;
            ans[pro[i].id] = j - st[pro[i].id].size();
        }
    

    但这样会很容易的被数据卡主,比如当所有的人的技能值都一样的时候。直接退化成一个 (O(n^2)) 的循环, (2e^5) 的数据范围肯定会炸。

    改良方法

    利用一个辅助数组,预处理最近一个比他小的位置。光用文字不是很好说,看一下代码然后手动模拟一遍应该就清楚了。

        int cnt=1,pre=1;
        Node now; // Node类型存的是人的信息
        for(int i=1;i<=n;++i){
            if(pro[i].r==now.r)
                cnt++;
            else{
                now = pro[i];
                cnt =1;
            }
            father[i] -=cnt;
        }
    

    然后我们在循环中就可以直接使用这个数组了

        for(int i=n;i>=1;--i)
            ans[pro[i].id] = (i+father[i]) - st[pro[i].id].size();
    

    这样这个循环就是一个稳定的 (O(n))

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+7;
    struct Node{
        int r,id;
        Node(){r=id=0;}
    }pro[maxn];
    set<int> st[maxn];
    int ans[maxn]={0},father[maxn]={0};
    bool cmp(Node a,Node b)
    {
        if(a.r==b.r)
            return a.id<b.id;
        return a.r<b.r;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        ios::sync_with_stdio(false);
        int n,k,x,y;
        cin>>n>>k;
        for(int i=1;i<=n;++i){
            cin>>pro[i].r;
            pro[i].id=i;
        }
        for(int i=1;i<=k;++i){
            cin>>x>>y;
            if(pro[x].r>pro[y].r)
                st[x].insert(y);
            else if(pro[x].r<pro[y].r)
                st[y].insert(x);
        }
        /*for(int i=1;i<=n;++i){
            cout<<i<<" ";
            for(set<int>::iterator it=st[i].begin();it!=st[i].end();++it)
                cout<<*it<<" ";
            cout<<endl;
        }
        cout<<endl;*/
        sort(pro+1,pro+1+n,cmp);
    
        int cnt=1,pre=1;
        Node now;
        for(int i=1;i<=n;++i){
            if(pro[i].r==now.r)
                cnt++;
            else{
                now = pro[i];
                cnt =1;
            }
            father[i] -=cnt;
        }
        /*for(int i=1;i<=n;++i)
            cout<<father[i]<<" ";
        cout<<endl;*/
        for(int i=n;i>=1;--i){
            ans[pro[i].id] = (i+father[i]) - st[pro[i].id].size();
        }
        for(int i=1;i<=n;++i)
            cout<<ans[i]<<" ";
        cout<<endl;
        return 0;
    }
    

    G - Petya's Exams

    题目大意:

    (n) 场考试,一共 (m) 天。每一场考试都有三个参数:(s) 通知有这场考试的那一天, (d) 考试的那一天,(c) 复习所需要的天数

    对于每一场考试,都必须复习足够的天数才能满足不挂科。

    现在让你输出让所有考试都能顺利通过的时间安排,如果解不存在,输出 (-1)

    数据保证每一场考试都不在同一天

    (有SPJ,所以只要输出合法即可)

    解题思路:

    贪心的思想。

    按每场考试结束的时间进行排序,然后从越早结束的考试开始,然后同考试通知的日期开始复习,直到天数足够。这样安排的过程中,如果出现日期冲突则说明解不存在。

    (我是根据样例发现的规律,感觉是没毛病的。但我不会证明。)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=110;
    struct Node{
        int s,d,c,id;
    }exam[maxn];
    int ans[maxn]={0};
    bool cmp(Node a,Node b)
    {
        return a.d<b.d;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        ios::sync_with_stdio(false);
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=m;++i){
            cin>>exam[i].s>>exam[i].d>>exam[i].c;
            exam[i].id=i;
            ans[exam[i].d] = m+1;
        }
        sort(exam+1,exam+1+m,cmp);
        bool flag=false;
        for(int i=1;i<=m;++i){
            int now = exam[i].s,cnt=0;
            while(cnt<exam[i].c&&now<exam[i].d)
            {
                //cout<<now<<endl;
                if(ans[now]==0){
                    ans[now] =exam[i].id;
                    cnt++;
                }
                now ++ ;
            }
            if(cnt<exam[i].c){
                //cout<<exam[i].id<<endl;
                flag=true;
                break;
            }
        }
        if(flag)
            cout<<-1<<endl;
        else{
            for(int i=1;i<=n;++i)
                cout<<ans[i]<<" ";
        }
        return 0;
    }
    

  • 相关阅读:
    微信小程序HTTPS
    微信商城-1简介
    va_list
    Event log c++ sample.
    EVENT LOGGING
    Analyze Program Runtime Stack
    unknow table alarmtemp error when drop database (mysql)
    This application has request the Runtime to terminate it in an unusual way.
    How to check if Visual Studio 2005 SP1 is installed
    SetUnhandledExceptionFilter
  • 原文地址:https://www.cnblogs.com/SCaryon/p/9043909.html
Copyright © 2011-2022 走看看