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
  • 相关阅读:
    poj 3321 Apple Tree
    hdu 1520 Anniversary party
    Light OJ 1089 Points in Segments (II)
    Timus 1018 Binary Apple Tree
    zoj 3299 Fall the Brick
    HFUT 1287 法默尔的农场
    Codeforces 159C String Manipulation 1.0
    GraphQL + React Apollo + React Hook 大型项目实战(32 个视频)
    使用 TypeScript & mocha & chai 写测试代码实战(17 个视频)
    GraphQL + React Apollo + React Hook + Express + Mongodb 大型前后端分离项目实战之后端(19 个视频)
  • 原文地址:https://www.cnblogs.com/diorvh/p/12032658.html
Copyright © 2011-2022 走看看