• 2020ICPC 昆明站 个人题解



    title : 2020ICPC 昆明站 个人题解
    date : 2022-11-21
    tags : ACM,题解,练习记录
    author : Linno


    2020ICPC 昆明站 个人题解

    题目链接:https://ac.nowcoder.com/acm/contest/12548

    补题进度:5/13

    H-Hard Calculation

    #include
    #define int long long
    using namespace std;
    
    void solve(){
    	int n;
    	cin>>n;
    	cout<<n+2020<<"\n"; 
    }
    
    signed main(){
    	ios::sync_with_stdio(0);
    	cin.tie(0);cout.tie(0);
    	int T=1;
    //	cin>>T;
    	while(T--){
    		solve();
    	} 
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    J-Parallel Sort

    我们可以把序列里面的环全部拉出来,并且对于一个环而言,展开成链,第一个和最后一个交换,第二个和倒数第二个交换,直到中间,这样一次操作可以保证把所有环都变成二元环,也因此操作最多不会超过2次。

    #include
    //#define int long long
    #define pii pair<int,int>
    #define mk make_pair
    #define F first
    #define S second
    using namespace std;
    const int N=1e5+7;
    
    int n,a[N],vis[N],mx,num,flag,idx;
    vector<vector<int>>vt;
    vector<int>tmp;
    vector<vector<pii>>ans;
    vector<pii>tmpp;
    
    void dfs(int x) {
    	vis[x]=1;
    	tmp.emplace_back(x);
    	if(vis[a[x]]) return;
    	dfs(a[x]);
    }
    
    signed main() {
    	ios::sync_with_stdio(0);
    	cin.tie(0);cout.tie(0);
    	cin>>n;
    	for(int i=1; i<=n; ++i) cin>>a[i];
    	num=0;
    	while(1){
    		flag=1,idx=0;mx=0;
    		for(int i=1;i<=n;++i) vis[i]=0;
    		for(int i=1;i<=n;++i){
    			if(a[i]!=i&&!vis[i]){
    				tmp.clear();
    				flag=0;
    				++idx;
    				dfs(i);  //把环全部拉出来
    				vt.emplace_back(tmp);
    			}
    		}
    		if(flag) break;
    		++num;
    		tmpp.clear();
    		for(int i=0;i<idx;++i){
    			int len=vt[i].size(),k=len/2;
    			if(len==2){
    				int x=vt[i][0],y=vt[i][1];
    				tmpp.emplace_back(mk(x,y));
    				swap(a[x],a[y]);
    				continue;
    			}
    			for(int l=1,r=len-1;l<r;++l,--r){
    				int x=vt[i][l],y=vt[i][r];
    				tmpp.emplace_back(mk(x,y));
    				swap(a[x],a[y]);
    			}
    		}
    		ans.emplace_back(tmpp);
    		vt.clear();
    		//for(int i=1;i<=n;++i) cout<
    	}
    	cout<<num<<"\n";
    	for(int i=0; i<num; ++i) {
    		cout<<ans[i].size()<<" ";
    		for(auto p:ans[i]){
    			if(p.F>p.S) swap(p.F,p.S);
    			cout<<p.F<<" "<<p.S<<" ";
    		}
    		cout<<"\n";
    	}
    	return 0;
    }
    /*
    11
    2 3 4 5 6 7 8 9 10 11 1
    
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    K-Riichi!!

    特判一开始胡的状态。先枚举要扔的牌,然后枚举摸的牌(这里根据听牌条件剪掉一些选择),然后再枚举对子,check一下是否胡就行了。同时要优化细节。

    #pragma GCC optimize("Ofast") 
    #include
    #include
    #include
    #include
    #include
    using namespace std;
    
    string str;
    int n,num[55],cnt[55];
    
    string ss[10][10]={
    {"1w","2w","3w","4w","5w","6w","7w","8w","9w"},
    {"1b","2b","3b","4b","5b","6b","7b","8b","9b"},
    {"1s","2s","3s","4s","5s","6s","7s","8s","9s"},
    {"1z","2z","3z","4z","5z","6z","7z"}
    };
    
    string sd(int x){
    	int p=x/9,q=x%9;
    	return ss[p][q];
    }
    
    int id(char x,char y){
    	int res;
    	if(y=='w') res=0;
    	else if(y=='b') res=1;
    	else if(y=='s') res=2;
    	else if(y=='z') res=3;
    	return res*9+(x-'1');
    }
    
    void check2(){
    	for(int i=0,x,y,z,k;i<=2;++i){
    		for(int j=0;j+2<9;++j){
    			x=i*9+j,y=x+1,z=x+2;
    			while(cnt[x]%3!=0){
    				cnt[x]--,cnt[y]--,cnt[z]--;	
    			}
    		}
    	}
    	for(int i=0;i<=33;++i) if(cnt[i]>=3) cnt[i]-=3; //去掉所有kezi 
    }
    
    bool check1(){
    	for(int i=0;i<=33;++i){
    		if(num[i]>=2){
    			for(int k=0;k<=33;++k) cnt[k]=num[k];
    			cnt[i]-=2;
    			check2(); 
    			int flag=1;
    			for(int k=0;k<=33;++k) if(cnt[k]) flag=0;
    			if(flag) return true;
    		}
    	}
    	return false;
    }
    
    signed main(){
    	ios::sync_with_stdio(0);
    	cin.tie(0);cout.tie(0);
    	cin>>n;
    	for(int t=1;t<=n;++t){
    		cin>>str;
    		for(int i=0;i<=33;++i) num[i]=0;
    		for(int i=0;i<28;i+=2){
    			++num[id(str[i],str[i+1])];
    		}
    		if(check1()){  //是否达到胡的状态 
    			cout<<"Tsumo!\n";
    			continue;
    		}
    		vector<pair<string,string>>ans;
    		for(int i=0;i<=33;++i){ //表示要扔掉的牌,这里只有14种情况 
    			if(!num[i]) continue;
    			--num[i];
    			string tmp="";
    			for(int j=0;j<=33;++j){ //剪掉没有或者附近没有的牌 
    				if(j==i||(!num[j]&&!(j>=1&&num[j-1])&&!num[j+1])) continue;
    				++num[j];
    				if(check1()) tmp+=sd(j);
    				--num[j];
    			}
    			if(tmp.size()) ans.emplace_back(make_pair(sd(i),tmp));
    			++num[i];
    		}
    		cout<<ans.size()<<"\n";
    		for(auto p:ans){
    			cout<<p.first<<" "<<p.second<<"\n";			
    		}
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    L-Simone and graph coloring

    最多用的颜色数即为最大团数,在这道题里其实就相当于求每个位置结尾的最长下降子序列,然后根据DP基础知识,排列可以稀疏性优化,就能 O ( n l o g n ) O(nlogn) O(nlogn)过了。

    #include
    #define int long long
    using namespace std;
    const int N=1e6+7;
    
    int a[N],b[N],dp[N],ans[N]; 
    
    void solve(){
    	int n;
    	cin>>n;
    	int mxlen=1;
    	for(int i=1;i<=n;++i){
    		cin>>a[i];
    		a[i]=-a[i]; //变成相反数就等于求最长下降子序列了 
    		int p=lower_bound(b+1,b+1+mxlen,a[i])-b-1; 
    		dp[i]=p+1;
    		b[dp[i]]=a[i];
    		mxlen=max(mxlen,p+1);
    	}
    	cout<<mxlen<<"\n"; //最大颜色数=最大团数
    	for(int i=1;i<=n;++i) cout<<dp[i]<<" \n"[i==n];
    	for(int i=1;i<=n;++i) a[i]=b[i]=dp[i]=ans[i]=0;
    }
    
    signed main(){
    	ios::sync_with_stdio(0);
    	cin.tie(0);cout.tie(0);
    	int T=1;
    	cin>>T;
    	while(T--){
    		solve();
    	} 
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    M-Stone Games

    主席树,每次询问求一个ans=x使得前x+1个位置的数×个数的总和是大于上一次x的。

    #include 
    #define int long long
    using namespace std;
    
    const int N=1e6+3;
    
    struct T{
    	int ls,rs;
    	long long sum;	
    }tr[N*40]; 
    
    long long rt[N],n,m,cre=0,a[N],maxi;
    #define mid ((l+r)>>1)
    
    int insert(int o,long long l,long long r,long long pos,long long val){
    	int p;
    	p=++cre;
    	tr[p]=tr[o];
    	if(l==r) {
    		tr[p].sum+=val*pos;
    		return p;	
    	}
    	if(pos<=mid) tr[p].ls=insert(tr[p].ls,l,mid,pos,val);
    	else tr[p].rs=insert(tr[p].rs,mid+1,r,pos,val);
    	tr[p].sum=tr[tr[p].ls].sum+tr[tr[p].rs].sum;
    	return p;
    }
    
    long long query(int p,int o,long long l,long long r,long long L,long long R){
    	if(l>r||l>R) return 0;
    	if(L<=l&&r<=R) return tr[p].sum-tr[o].sum;
    	long long sum=0;
    	if(L<=mid) sum+=query(tr[p].ls,tr[o].ls,l,mid,L,R);
    	if(R>mid) sum+=query(tr[p].rs,tr[o].rs,mid+1,r,L,R);
    	return sum;
    }
    
    signed main(){
        ios::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
    	cin>>n>>m;
    	maxi=1; 
    	for (int i=1;i<=n;++i) {
    		cin>>a[i];
    		maxi=max(a[i],maxi);
    	}
    	for (int i=1;i<=n;++i){
    		rt[i]=insert(rt[i-1],1,maxi,a[i],1);
    	} 
    //	cout<
    	for(long long i=1,lp,rp,l,r,lst=0,x;i<=m;++i){
    		cin>>lp>>rp;
    		l=min((lp+lst)%n+1,(rp+lst)%n+1);
    		r=max((lp+lst)%n+1,(rp+lst)%n+1);
    		x=0,lst=query(rt[r],rt[l-1],1,maxi,1,x+1);
    	//	cout<
    		while(lst>x){
    			x=lst;
    			lst=query(rt[r],rt[l-1],1,maxi,1,x+1);
    		//	cout<
    		}
    		++lst;
    		cout<<lst<<"\n";
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
  • 相关阅读:
    【电路基础1】电阻
    python+django医院设备综合管理系统vue363
    理解编码器M法/T法M\T法转速测量原理
    【JAVA】LinkedList与链表(Part2)
    docker配置镜像代理
    JavaSPI详解
    [ROC-RK3568-PC] [Firefly-Android] 10min带你了解PWM的使用
    MySQL事务原理(InnoDB引擎)
    腐烂橘子图问题
    Nacos服务发现原理分析
  • 原文地址:https://blog.csdn.net/SC_Linno/article/details/127957098