zoukankan      html  css  js  c++  java
  • ARC125 ABCD

    ARC125 ABCD

    A.

    题意

    给定01序列(A),问能否通过如下三种操作生成序列(B),满足(B = T)

    • 将序列(A)整体右移一位
    • 将序列(A)整体左移一位
    • 将当前(A)的第一个元素复制到(B)的末尾

    输出最少操作次数

    分析

    有一种显然的贪心方法:找到(A)中01分界的位置,然后每次在这个位置左右移动。这样答案的两部分分别是移动到分界处和左右移动,后半部分答案不会有区别,前半部分答案只需按照左移和右移讨论取min即可,这样就变成了一道模拟题

    代码

    int main(){
        int n = rd();
        int m = rd();
        VI a(n);
        VI b(m);
        int vis1[2] = {0};
        int vis2[2] = {0};
        for(int i = 0;i < n;i++)
    	a[i] = rd(),vis1[a[i]]++;
        for(int i = 0;i < m;i++)
    	b[i] = rd(),vis2[b[i]]++;
        if((vis2[0] && !vis1[0]) || (vis2[1] && !vis1[1])) {
    	puts("-1");
    	return 0;
        }
        if(!vis2[0]) {
    	int mi = 1e9;
    	for(int i = 0;i < n;i++)
    	    if(a[i] == 1) {
    		mi = i;
    		break;
    	    }
    	for(int i = n - 1,j = 1;i > 0;i--,j++)
    	    if(a[i] == 1){
    		mi = min(mi,j);
    		break;
    	    }
    	printf("%d",mi + m);
    	return 0;
        }
        
        if(!vis2[1]) {
    	int mi = 1e9;
    	for(int i = 0;i < n;i++)
    	    if(a[i] == 0) {
    		mi = i;
    		break;
    	    }
    	for(int i = n - 1,j = 1;i > 0;i--,j++)
    	    if(a[i] == 0){
    		mi = min(mi,j);
    		break;
    	    }
    	printf("%d",mi + m);
    	return 0;
        }
    
        int pos = -1;
        int mi = 1e9;
        for(int i = 0;i <= n - 1;i++){
    	if(a[i] != a[(i + 1) % n]) {
    	    pos = i;
    	    if(a[i] != b[0]) pos++;
    	    mi = min(mi,pos);
    	    pos = n - i - 1;
    	    if(a[(i + 1) % n] != b[0]) pos++;
    	    mi = min(mi,pos);
    	}
        }
        mi++;
        for(int i = 1;i < m;i++){
    	if(b[i] != b[i - 1]) mi += 2;
    	else mi++;
        }
        printf("%d",mi);
    }
    

    B.

    题意

    求满足(x^2 - y)是平方数的((x,y))个数

    (1 leq x,yleq N),(1 leq N leq 10^{12})

    分析

    [x^2 - y = z^2\ (x+z)(x-z) = y ]

    (p = x + z,q = x - z)

    有如下约束

    • (q leq p)
    • (p + q equiv 0 (mod 2))
    • (1leq frac{p+q}{2} leq N)
    • (1 leq pq leq N)

    容易知道((p,q))的解和((x,y))一一对应

    用第一个和最后一个约束可以知道(q leq sqrt{N}) ,因此只需要枚举(q)

    代码

    int main(){
        ll n = rd();
        int ans = 0;
        for(ll i = 1;(ll)i * i <= n;i++){
    	ll r = n / i;
    	add(ans,((r - i + 1) / 2) % MOD);
    	if(((r & 1) ^ (i & 1)) == 0) add(ans,1);
        }
        printf("%d",ans);
    }
    

    C.

    题意

    给定长度为(k)的值域在([1,n])的递增序列,要求构造一个([1,n])的排列使得原序列是排列的一个(LIS)

    [1 leq k leq n leq 2 imes 10^5 ]

    分析

    这题可以用Dilworth's theorem比较巧妙地构造,如果能够保证排列可以由k个极长递减子序列构成,就能保证排列的(LIS)长度为(k),这样原序列一定会是一个(LIS)

    于是只需要贪心构造,用原序列的每个元素来作为极长递减子序列的开头(最后一个特殊处理),把未出现的元素中最小的数填到开头的后面。剩下的全放到最后一个那里就行了

    代码

    int main(){
        int n = rd();
        int k = rd();
        VI v(k + 1);
        VI vis(n + 1);
        for(int i = 1;i <= k;i++)
            v[i] = rd(),vis[v[i]] = 1;
        int now = 1;
        for(;now <= n && vis[now];now++);
        for(int i = 1;i < k;i++){
            printf("%d ",v[i]);
            if(now < v[i]) {
                vis[now] = 1;
                printf("%d ",now);
                for(;now <= n && vis[now];now++);
            }
        }
        for(int i = n;i > v[k];i--)
            if(!vis[i]) printf("%d ",i);
        printf("%d ",v[k]);
        for(int i = v[k] - 1;i >= 1;i--)
            if(!vis[i]) printf("%d ",i);
    }
    

    D.

    题意

    给定长度为(N)的数组(A),求其中只出现过一次的子序列的个数

    [1 leq N leq 2 imes 10^5,1 leq A_i leq N ]

    分析

    容易想到(dp),考虑(dp[i])表示([1,i])中以(a[i])为结尾的满足条件的子序列的个数,观察性质,当相同的数再次出现时,前一个数能构成的所有子序列都会重复,因此这里要减去贡献,显然减法的操作只会在这种情况产生。考虑(dp[i])时哪些是合法的转移,显然就是上一次出现的位置到当前位置的所有子序列都可以接上(a[i]),之前的不合法。

    [dp[i] = sum_{j = lst}^{i-1} dp[j] ]

    (dp[lst] = 0)

    支持区间询问,单点修改的数据结构即可

    代码

    struct BIT{
        int n;
        int c[maxn];
        inline void ADD(int pos,int x){
            for(;pos <= n;pos += pos & -pos){
                add(c[pos],x);
            }
        }
        inline int ask(int pos){
            int ans = 0;
            for(;pos > 0;pos -= pos & -pos)
                add(ans,c[pos]);
            return ans;
        }
        inline int ask(int l,int r){
            if(l > r) return 0;
            int ans = ask(r);
            add(ans,MOD - ask(l - 1));
            return ans;
        }
    }bit;
    
    int main(){
        int n = rd();
        bit.n = n + 5;
        VI v(n + 1);
        VI pre(n + 1);
        VI pos(n + 1);
        for(int i = 1;i <= n;i++){
            v[i] = rd();
            pre[i] = pos[v[i]],pos[v[i]] = i;
        }
        bit.ADD(1,1);
        for(int i = 2;i <= n;i++){
            int l = pre[i];
            int tmp = bit.ask(l,i - 1);
            if(l) bit.ADD(i,tmp);
            else bit.ADD(i,tmp + 1);
            int TMP = bit.ask(l,l);
            if(l > 0) bit.ADD(l,MOD-TMP);
        }
        printf("%d",bit.ask(n));
    }
    
  • 相关阅读:
    组合两个表(sql查询语句)
    The six Day 数组中找出和为目标值
    实时监控-CPU
    使用 python 的细碎总结
    Visual Studio 2017 运行、调试使用CMake构建的多可执行程序项目
    git 学习笔记 —— 在不同的提交间进行切换和重置( git reset/reflog/tag 命令)
    git 学习笔记 —— 保留/丢弃当前分支修改并切换至其他分支
    git 学习笔记 —— 获取远端仓库以及提交信息至远端 git remote/fetch/branch
    git 学习记录—— git 中的仓库、文件状态等概念介绍
    VScode 配置 C++ 环境进行编译和调试
  • 原文地址:https://www.cnblogs.com/hznumqf/p/15309235.html
Copyright © 2011-2022 走看看