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;
    }
    
  • 相关阅读:
    linux下C语言socket网络编程简例
    cJSON学习笔记 续集
    用javac编译整个j2ee项目
    如何用javac 和java 编译运行整个Java工程
    Log4j 日志级别
    (获取选中的光标起始位置)EditText常用属性【三】:EditText选取操作
    Linux下启动和停止Java应用程序的Shell脚本
    (判断url文件大小)关于inputStream.available()方法获取下载文件的总大小
    java 从网络Url中下载文件
    JavaMail入门:创建纯文本、HTML格式的邮件
  • 原文地址:https://www.cnblogs.com/tuchen/p/15257548.html
Copyright © 2011-2022 走看看