zoukankan      html  css  js  c++  java
  • 哪吒闹海

    哪吒闹海

    题目描述
    传说中,东海龙宫有一副绝世法宝——n张神迹卡牌,每张卡牌上都写着一个数字。哪吒闹海时,想要施法将龙宫这n张卡牌毁灭,若当前剩余的卡牌数量为k,哪吒就可以施法将所有数字为k的卡牌销毁,这样的操作可以一直进行到没有卡牌可以被毁灭为止。
    但哪吒发现,只进行这样的操作可能没办法把所有卡牌消灭,于是他借来了师父太乙真人的法宝,使用一次可以将一张卡牌上的数字改变成他想要的任意一个其他数字。
    但是东海龙王发现了哪吒的企图,于是东海龙王会进行m次修改操作,第i次将第xi张卡牌的数字改变为yi,每次东海龙王进行一次操作后,哪吒都想知道至少使用多少次法宝才可以将所有卡牌消灭。
    输入
    第一行两个整数n,m
    第二行n个整数代表n张卡牌上的数字
    接下来m行,每行两个整数x,y,表示将第x张卡牌上的数字改为y
    输出
    m行,每行输出一个数字,代表第i次操作后至少用多少次法宝才能将卡牌消灭
    样例输入 Copy
    5 3
    1 1 3 4 5
    1 2
    2 5
    5 4
    样例输出 Copy
    0
    1
    1
    提示
    对于40%的数据 n,m<=200
    对于60%的数据 n,m<=2000
    对于100%的数据 n<=200000,m<=200000
    卡牌上的数字始终<=n

    题解:

    用ans表示不会哪吒不会修改的数字个数
    设num[i] 为 i这个数字 出现的次数,tot[i] 为i 这个状态 出现的次数,这个总体上可以分为两个操作,一个是添加一个数, 一个是删除一个数字,输入的时候相当于添加, 修改的时候相当于先删除后添加。
    对于删除操作,对于数字i , 出现次数为num[ i ] , 那么将i数字删除,令k = i - num[i](k >= 0) , 这个时候如果tot[k] 不等于0 , 也就是这个k状态已经出现过, 这个时候就表明会有另外一个点p , 删除p点 , 则会有k = p - num[p] , 如果我将i点删除走向k,如果没有p点,则会k1 = k - num[k] ,但是此时有p点, 到p点的时候我们又会走向k点, 此时哪吒还要再辛苦一番,再修改一下别的数 , 所以这个时候会增加答案的贡献, 相反我们碰到tot[k] == 0 , 那么就将这个数字直接删除, ans – ,
    对于添加操作,同理, 如果tot[k] == 0 . 表示没有这个状态没有走过, 那么这个点就不用被删掉了,则ans ++ ,
    最后输出答案的时候就是n - ans
    总结就是删除的时候,这个状态没有被走过的话, 就直接将这个数字删除 , ans --, 否则留着会增加答案贡献, 添加的时候,如果这个状态没有被走过,那么这个数字就不用被删除 , ans ++

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 2e5 + 10 ;
    int a[N] , num[N] , tot[N] ;
    int ans = 0 ;
    void add(int x)
    {
    	num[x] ++ ;
    	if(x - num[x] >= 0)
    	 {
    	 	if(!tot[x - num[x]]) ++ ans ; // 没有被走过,这个点不用删
    	 	tot[x - num[x]] ++ ;
    	 }
    }
    void del(int x)
    {
    
    	if(x - num[x] >= 0)
    	 {	
    	    tot[x - num[x]] -- ;
    	 	if(!tot[x - num[x]]) -- ans ; // 
    	 
    	 }	
    	 num[x] -- ;
    }
    int main()
    {
    	int n , m ;
    	scanf("%d%d" , &n , &m) ;
    	for(int i = 1; i <= n ;i ++)
    	 scanf("%d" , &a[i]) , add(a[i]) ;
    	cout << ans << endl ;
    	while(m --)
    	{
    		int x , y ;
    		scanf("%d%d" , &x , &y) ;
    		del(a[x]) , add(a[x] = y) ;
    		printf("%d
    " , n - ans) ;
    	}
    	return 0 ;
    }
    
    每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。
  • 相关阅读:
    @FeignClient同一个name使用多个配置类报错,解决方案【转+改进】
    spring cloud 与spring boot 版本不匹配引发的问题总结
    无聊系列
    基于redis+lua实现的分布式限流
    elasticsearch 优化笔记
    redis+lua库存扣减和冲正
    es-dsl笔记
    wiki—-Confluence搭建
    Linux常用命令
    SQLSERVER|CDC 日志变更捕获机制
  • 原文地址:https://www.cnblogs.com/spnooyseed/p/12870872.html
Copyright © 2011-2022 走看看