zoukankan      html  css  js  c++  java
  • 【日记】12.12

    12.12日记

    CF

    1. 1234D:https://codeforces.com/problemset/problem/1234/D

    其实直接对每个字母建一个树状数组,建26个即可。每次询问区间和,如果不为0,说明有这个字母,答案+1。时间复杂度(O(26nlog n))

    #include<bits/stdc++.h>
    using namespace std;
    const int M=1e5+20;
    int c[27][M],n;
    char s[M];
    inline int lowbit(int x){return x&(-x);}
    inline void operate(int pos,int k){
        for (int i=pos;i<=n;i+=lowbit(i))
            c[s[pos]-'a'][i]+=k;
    }
    inline int query(int ch,int x){//1-x的和
        int ans=0;
        for(int j=x;j;j-=lowbit(j))
            ans+=c[ch][j];
        return ans;
    }
    inline int BITquery(int l,int r){
        int ans=0;
        for(int i=0;i<=25;++i)
            ans+=(query(i,r)!=query(i,l-1));
        return ans;
    }
    int main(){
        scanf("%s",s+1);
        n=strlen(s+1);
        for(int i=1;i<=n;++i)
            operate(i,1);
        int q;
        scanf("%d",&q);
        for(int i=1;i<=q;++i){
            int op;
            scanf("%d",&op);
            if (op==1){
                int pos;
                char sc[2];
                scanf("%d%s",&pos,sc);
                operate(pos,-1);
                s[pos]=sc[0];
                operate(pos,1);
            }
            else{
                int l,r;
                scanf("%d%d",&l,&r);
                printf("%d
    ",BITquery(l,r));
            }
        }
        return 0;
    }
    
    1. 1185C2:https://codeforces.com/problemset/problem/1185/C2

    这道题可以转化成:1-i区间内,挑出尽可能多的数,同时保证和<M-a[i+1]。那么很容易想到,应该从小到大挑数。但每次区间里各个数的数量都在变化,不太容易用普通数据结构维护,因此可以考虑暴力。

    就是直接设置tot数组,存储目前为止,各个数字出现的次数。这样每次都从小往大暴力统计和,找到可以挑出的数的最大个数,再一减就得到答案了。

    时间复杂度(O(100n))

    还有一个(O(nlog ^2n))的做法,就是首先读入后排序,然后再按原来顺序依次读入数据,建立树状数组,放到对应的排序后的位置上,然后维护区间和(和区间数的个数,相当于两个树状数组),之后二分询问区间和(1-x),找到最靠右的x,满足区间和<M-a[i+1]。这样也可以。如果考试时间比较大的时候,那么就可以采用这种思想,不过写起来也超级麻烦。

    #include<bits/stdc++.h>
    using namespace std;
    const int M=2e5+20;
    int tot[105];
    int main(){
    	int n,m;
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i){
    		int c;
    		scanf("%d",&c);
    		int T=m-c,p=1;
    		while(p<=100&&T>=tot[p]*p)
    			T-=tot[p]*p,++p;
    		int ans=0;
    		for(int j=1;j<=p-1;++j)
    			ans+=tot[j];
    		ans+=T/p;
    		printf("%d",max(i-ans-1,0));
    		if(i!=n)
    			putchar(' ');
    		++tot[c];
    	}
    	putchar('
    ');
    	return 0;
    }
    
    1. 1163B2:https://codeforces.com/problemset/problem/1163/B2

    要求1-i区间的数,满足删掉一个之后,所有数出现次数相同。求出最大的i。

    思路:开1e5个set,s[i]存放出现次数为i的数都有哪些。另外再开数组存储每个数出现的次数(即对应的集合)。再记录出现次数的最大值mx,那么满足条件只有两种情况:

    • mx=1,所有数都只出现了一次,那么随便删一个就行了,肯定满足。
    • 出现次数为mx的只有一个数,剩下的数都是出现了mx-1次的。这可以用总数来判断。这样的话把mx次的那个删一个就可以了。

    那么这题就秒了。复杂度(O(nlog n))

    #include<bits/stdc++.h>
    using namespace std;
    const int M=1e5+20;
    unordered_set<int> s[M];
    int cnt[M];
    int main(){
    	int n,ans=0,mx=0;
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i){
    		int c;
    		scanf("%d",&c);
    		s[cnt[c]].erase(c);
    		++cnt[c];
    		s[cnt[c]].insert(c);
    		if (mx<cnt[c])
    			mx=cnt[c];
    		if ((s[mx].size()==1&&s[mx].size()*mx+s[mx-1].size()*(mx-1)==i)||(s[mx].size()*mx==i-1)||(mx==1))
    			ans=i;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

    明日计划

    1. 树直径,重心,树链剖分
    2. CDQ
  • 相关阅读:
    企业网络架构
    谷歌推出情境感知API
    Firebase远程更新应用
    黑盒测试
    单元测试
    代码性能分析
    代码静态检查
    PHP 使用正则匹配 去掉 URL 链接第三个斜杠后面的部分
    JQ 全选 反选 取消全选的方法
    织梦导航栏有特定样式用法
  • 原文地址:https://www.cnblogs.com/diorvh/p/12032658.html
Copyright © 2011-2022 走看看