zoukankan      html  css  js  c++  java
  • AtCoder ARC 125 部分题解

    A - Dial Up

    找到最近的与第一个位置不同的数字的位置,第一次转换需要这个距离的代价,之后的转换只需要 (1) 的代价左右切换即可

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 200010;
    const int INF = 1000000007;
    
    int n, m;
    int a[maxn], b[maxn];
    
    ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
    
    int main(){
    	n = read(), m = read();
    	
    	int l = INF, r = INF;
    	for(int i = 1 ; i <= n ; ++i) {
    		a[i] = read();
    		if(i > 1 && a[i] != a[1]) r = min(r, i-1);
    	}
    	for(int i = 1 ; i <= m ; ++i) b[i] = read();
    	
    	for(int i = n ; i >= 2 ; --i) if(a[i] != a[1]){
    		l = n-i+1; break;
    	}
    
    	int cur = a[1], ans = 0, flag = 0;
    	
    	for(int i = 1 ; i <= m ; ++i){
    		if(cur != b[i]){
    			ans += (flag == 0) ? min(l, r) : 1;
    			cur ^= 1;
    			flag = 1;
    		}
    		++ans;
    	}
    	
    	if(ans >= INF) printf("-1
    ");
    	else printf("%d
    ", ans);
    	
    	return 0;
    }
    

    B - Squares

    注意移项后可以变成平方差公式,分解后变为 ((x+t)(x-t)=y),令 (p=(x+t),q=(x-t)),则原问题转化成计数 ((p,q)) 对的数量,满足

    • (q <= p)
    • (frac{p+q}{2}=x)
    • (pq leq n)
    • (q equiv p mod 2)
    • (q leq p leq frac{n}{q})
      枚举 (q) 即可,(q) 不超过 (sqrt n)
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int M = 998244353; 
    
    ll n;
    
    ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
    
    int main(){
    	n = read();
    	int ans = 0;
    	for(int i = 1 ; i <= (int)sqrt(n+0.5) ; ++i){
    		ll l = i, r = n / i;
    		if((r-l+1)&1) {
    			ll len = (r-l)/2;
    			ans = (ans + len % M + 1) % M;
    		} else{
    			ll len = (r-l+1)/2;
    			ans = (ans + len % M) % M;
    		} 
    	}
    	printf("%d
    ", ans);
    	return 0;
    }
    

    C - LIS to Original Sequence

    题意:

    给定一个排列,给定其中的一个最长上升子序列,求满足条件的字典序最小的排列

    题解:

    如果要求最长上升子序列长度为 (k),则序列中一定有 (k) 个连续的的下降段,这样保证同一下降段中的数不会形成上升序列,不同下降段中的数形成上升序列,且长度为 (k),贪心构造即可

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 200010;
    const int INF = 1000000007;
    
    int n, k;
    int a[maxn]; 
    int vis[maxn];
    
    ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
    
    int main(){
    	n = read(), k = read();
    	for(int i = 1 ; i <= k ; ++i) a[i] = read(), vis[a[i]] = 1;
    	
    	int cur = 1;
    	while(vis[cur]) ++cur;
    	for(int i = 1 ; i < k ; ++i){
    		printf("%d ", a[i]);
    		if(cur < a[i]) {
    			printf("%d ", cur);
    			cur++;
    			while(vis[cur]) ++cur;	
    		}
    	}
    	for(int i = n ; i > max(a[k], cur) ; --i){
    		if(!vis[i]) printf("%d ", i);
    	}
    	printf("%d ", a[k]);
    	for(int i = a[k]-1 ; i >= cur ; --i){
    		if(!vis[i]) printf("%d ", i);
    	} printf("
    ");
    	return 0;
    }
    

    D - Unique Subsequence

    题意:

    给定一个序列,求有多少个子序列在该序列中只出现一次

    题解:

    (dp[i]) 表示第 (i) 个元素必选,序列前 (i) 个元素中,子序列只出现一次的数量,则若 (f[i]) 能转移到 (f[j]),要满足 ((i,j)) 区间中不出现 (a[i],a[j]),否则生成的子序列不唯一

    所以 (f[i]) 统计的答案即为 ((pre[i],i-1)) 中不含 (a[j])(f[j]) 之和,可以使用树状数组维护,只维护当前每个值最后一个位置的 (f),因为每个值只有最后一个位置会对答案产生贡献,统计答案只统计每个值最后一个位置的 (f)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 200010;
    const int INF = 1000000007;
    
    int n, k;
    int a[maxn]; 
    int vis[maxn];
    
    ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
    
    int main(){
    	n = read(), k = read();
    	for(int i = 1 ; i <= k ; ++i) a[i] = read(), vis[a[i]] = 1;
    	
    	int cur = 1;
    	while(vis[cur]) ++cur;
    	for(int i = 1 ; i < k ; ++i){
    		printf("%d ", a[i]);
    		if(cur < a[i]) {
    			printf("%d ", cur);
    			cur++;
    			while(vis[cur]) ++cur;	
    		}
    	}
    	for(int i = n ; i > max(a[k], cur) ; --i){
    		if(!vis[i]) printf("%d ", i);
    	}
    	printf("%d ", a[k]);
    	for(int i = a[k]-1 ; i >= cur ; --i){
    		if(!vis[i]) printf("%d ", i);
    	} printf("
    ");
    	return 0;
    }
    
  • 相关阅读:
    我要好offer之 二叉树大总结
    我要好offer之 字符串相关大总结
    楼层扔鸡蛋问题[转]
    Linux System Programming 学习笔记(十一) 时间
    Linux System Programming 学习笔记(十) 信号
    Linux System Programming 学习笔记(九) 内存管理
    Linux System Programming 学习笔记(八) 文件和目录管理
    Linux System Programming 学习笔记(七) 线程
    Linux System Programming 学习笔记(六) 进程调度
    APUE 学习笔记(十一) 网络IPC:套接字
  • 原文地址:https://www.cnblogs.com/tuchen/p/15257548.html
Copyright © 2011-2022 走看看