National Contest for Private Universities (NCPU), 2019 C题 Boxes

   这道题数组模拟双向链表,其实就是将单向链表改成双向的,左右两个数组标记一下即可,循环链表将头尾连接即可。 

题意:给出一个数n,表示存在一个整数序列1……n,然后进行四种操作:

           操作一:输入x,y,表示将x移到y的左边(若x本来就在y的左边则忽略);

           操作二:输入x,y,表示将x移到y的右边(若x本来就在y的右边则忽略);

           操作三:输入x,y,表示交换x和y。

           操作四:将整个序列倒置。

           最后求操作后的整个序列奇数项的和。
思路:这个题很巧妙,在整个过程中,逆序操作最耗时间,由于题目只需要求奇数项的和,在进行逆序操作时,不用真的进行操作,只需要记录逆序的次数即可,若是奇数次,则最后求整个序列的偶数项之和,偶数次就是求奇数项之和。还有一点,操作四的进行与否会对前两种操作有一点影响,需要稍作处理。  

借鉴博客https://blog.csdn.net/acm_fighting/article/details/50983756

AC代码:
 

#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <string>
using namespace std;
typedef long long LL;
const int maxn= 100010;
int left[maxn],right[maxn];

void link(int L, int R) {       //连接L和R,L在左边
    right[L] = R;
    left[R] = L;
}
int main() {
    int n,m;
    while(~scanf("%d%d",&n,&m)) {
        for(int i=0; i<=n; i++) {
            link(i,i+1);
        }
        //循环链表 
//        left[0]=n;
//        right[n]=0;
        int op,flag=0,x,y;
        while(m--) {
            scanf("%d",&op);
            if(op==4) {         //判断是否进行逆序操作
                flag=!flag;
                continue;       
            }
            scanf("%d%d",&x,&y);
            if(op==3 && right[y]==x)    swap(x,y);  //方便后面判断交换是否相邻
            
            if(op!=3 && flag) op=3-op;          //进行逆序操作后,原来的左边变成右边,右边变成左边
            
            if(op==1 && left[y]==x) continue;
            if(op==2 && right[y]==x) continue;
            int lx=left[x],rx=right[x],ly=left[y],ry=right[y];
            if(op==1) {                 //将x移到y的左边
                link(lx,rx);   //x左右相连
                link(ly,x);    //y左和x
                link(x,y);     //x和y
            } else if(op==2) {          //将x移到y的右边
                link(lx,rx);    //x左右相连
                link(y,x);      //y和x
                link(x,ry);     //x和y右
            } else if(op==3) {          //交换x和y
                if(right[x]==y) {       //当x和y相邻时
                    link(lx,y);
                    link(y,x);
                    link(x,ry);
                } else {                //当x和y不相邻时
                    link(lx,y);
                    link(y,rx);
                    link(ly,x);
                    link(x,ry);
                }
            }
        }
        LL sum=0;
        int b=0;
        for(int i=1; i<=n; i++) {
            b=right[b];
            if(i%2) 
				sum+=b;
        }
        if(flag && n%2==0) 
			sum=(LL)n*(n+1)/2-sum;
        //如果逆序操作次数为奇数,则最终结果求的是整个序列的偶数项之和,此处是用 序列总和减去奇数项之和
        printf("%lld\n",sum);
        
    }
    return 0;
}

   我用vector做的,但是C++11报运行时错误,C++11报运行时错误,1e5也没道理越界诶 奇奇怪怪...   有聚聚们知道错误地方的话请告知嗷

我的代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int m,n;
    while(scanf("%d%d",&n,&m)!=EOF){
		vector<int> vt;
		long long ans = 0;
    	for(int i=1;i<=n;i++)
    		vt.push_back(i);
		while(m--) {
    		int op,a,b;
    	 
    		cin>>op;
			if(op==1||op==2||op==3)
				cin>>a>>b;
    		if(op==1) {
    			// x 在 y 左边 
    			vector<int>::iterator iter1=find(vt.begin(),vt.end(),a);
    			vector<int>::iterator iter2=find(vt.begin(),vt.end(),b);

    			for(int i=0;i<=(iter2-iter1-2);i++) {
    				*(iter1+i)=*(iter1+i+1); 
				}
				*(iter2-1)=a;
					
			}
			if(op==2) {
				// x 在 y 右边 
				vector<int>::iterator iter1=find(vt.begin(),vt.end(),a);
    			vector<int>::iterator iter2=find(vt.begin(),vt.end(),b);
    			for(int i=0;i<=(iter2-iter1-1);i++) {
    				*(iter1+i)=*(iter1+i+1); 
				}
				*iter2=a;
			} 
			if(op==3) {
				//交换 x y 
				vector<int>::iterator iter1=find(vt.begin(),vt.end(),a);
    			vector<int>::iterator iter2=find(vt.begin(),vt.end(),b);
    			*iter1=b;
				*iter2=a; 
			} 
    		if(op==4) {
    			reverse(vt.begin(),vt.end());
			} 
		}
//    	for(int i=0;i<n;i++)
//    		cout << vt[i] << " ";
    	for(int i=0;i<n;i+=2)
			ans += vt[i]; 
		cout << ans << endl;
		vt.clear();
	}
    
    return 0;
}
发布了87 篇原创文章 · 获赞 56 · 访问量 9148

猜你喜欢

转载自blog.csdn.net/Ven21959/article/details/101155684