• %你赛题解


    %你赛考试解题报告

    $ T1 $.(追求 $ AK $ ):

    对于(60)分的数据 , 这个范围内的数据是纯随机的,而且不会有什么卡人的地方(因为随机的话并随机不出来(happiness)这个单词)。这些分数大概就是写挂了的同学得到的分数。

    对于另外(40)分的数据 , 感谢由(wucstdio)亲自手造数据,这个范围内的数据卡了很多的东西.


    说了这么多,我们开始考虑正解怎么写。

    首先题面的意思就是,如果你不能在交换两个字符后使得(happiness)不是原字符串的字串,就输出(No),那么我们可以很显然的想到,对于交换两个字符后,最多使得2个(happiness)从原字符串中消失。那么,我们可以做一遍(KMP)(因为数据范围较小,暴力模拟也可以)跑出在原来的字符串中有多少个(happiness)。所以,如果最后你发现(happiness)的个数(num)(2)要大,那么无论你怎么换,最后一定会有一个或者多个(happiness)出现在原来的字符串中,对于这种情况,我们可以直接输出(No)

    然后我们来考虑(num <= 2)的情况 ,当(num = =2)时,很显然的,我们需要在这两个(happiness)中交换。但是需要注意一点,我们必须保证交换之后的字符串中不出现新的(happiness)这个单词,所以当我们枚举交换哪一位的时候,我们需要考虑一下交换之后的前缀和后缀,之后再交换就可以了。

    (num == 1)的情况时,交换的方法和当(num == 2)的时候并没有多大区别。

    所以我们来考虑一下当(num==0)的时候的情况 , 在(num==0)的情况时,我们只需要保证在交换之后不会出现新的(happiness)这个单词即可。(注意换的时候考虑一下前缀和后缀就好了)**

    激动人心的代码时间:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    
    
    using namespace std;
    
    const int N = 2e5 + 10;
    
    char s[N];
    char h[10] = { '0' , 'h' , 'a' , 'p' , 'p' , 'i' , 'n' , 'e' , 's' , 's' }; 
    int num , start[N];
    
    int main ( void ) {
    	scanf ( "%s" , s + 1 );
    	int len = strlen ( s + 1 );
    	int now = 1;
    	for ( int i = 1 ; i <= len ; i++ ) {
    		if ( s[i] == h[now] ) {
    			if ( now == 9 ) {
    				num++;
    				start[num] = i - 9 + 1;
    				now = 1;
    				continue;
    			}
    			else {
    				now++;
    				continue;
    			}
    		}
    		else if ( s[i] != h[now] ) {
    			now = 1;
    			if(s[i]==h[now])now++;
    			continue;
    		}
    	}
    	if ( num >= 3 ) {
    		puts ( "NO" );
    		return 0;
    	}
    	else {
    		if ( num == 2 ) {
    			puts ( "YES" );
    			printf ( "%d %d
    " , start[1] + 1 , start[2] + 2 );
    			return 0;
    		}
    		if ( num == 1 ) {
    			puts ( "YES" );
    			printf ( "%d %d
    " , start[1] + 3 , start[1] + 4 );
    			return 0;
    		}
    		if ( num == 0 ) {
    			if ( s[1] != 'h' && s[1] != 'a' ) {
    				puts ( "YES" );
    				printf ( "%d %d
    " , 1 , 2 );
    				return 0;
    			}
    			else {
    				if ( s[1] == 'h' ) {
    					for ( int i = 2 ; i <= len ; i++ ) {
    						if ( s[i + 1] != 'a' ) {
    							puts ( "YES" );
    							printf ( "%d %d
    " , 1 , i ); 
    							return 0;
    						}  
    					}
    				}
    				else if ( s[1] == 'a' ) {
    					for ( int i = 2 ; i <= len ; i++ ) {
    						if ( s[i + 1] != 'p' ) {
    							puts ( "YES" );
    							printf ( "%d %d
    " , 1 , i ); 
    							return 0;
    						}
    					}
    				} 
    			} 
    		}
    	}
    	return 0;
    }
    

    $ T2 $ . (亚运会):

    我才不会告诉你这道题本来是一道大毒瘤模拟然后前几天才改的题呢

    题面写的应该挺清楚的,我在这里就不重新讲一遍了。

    首先对于(30)分的数据,(n , m <=1000)直接(n)(Spfa or Dijkstra)判断联通性,没了

    然后考虑(60)分的数据,象征性的给一些常数写的大的同学,没有什么实际意义

    直接考虑正解:

    我们可以很显然的发现,对于在这一张图中的点 , 如果它们在一个强连通分量中 , 那么一定可以相互到达 , 所以我们可以对这张图进行(Tarjan)缩点,然后考虑缩点后的新图。我们知道,缩点之后的一张图,一定是一个(DAG)。那么我们考虑一下这张图上的(Topsort)。我们在(Topsort)的过程中,如果发现了同时有两个点的入度为零,那么我们直接输出(No).

    为什么?
    我们知道,在(Topsort)的过程中,如果同时出现了两个入度为(0)的点,那么这两个点之间一定是不可以相互到达的。因为一个点在跑完它自己的(Topsort)后并不会经过另一个入度为(0)的点。那么这就是这道题的依据

    代码时间:

    #include <cstdio>
    #include <cstring>
    #include <stack>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 100010;
    
    struct Edge{
        int s;
        int e;
        int next;
    }edge1[N],edge2[N];
    stack <int> st;
    int n,m,e_num1,e_num2,vis_num,cnt;
    int head[N],instack[N],low[N],tim[N],belong[N],de[N];
    
    inline int Read () {
        int s = 0 , w = 1;
        char ch = getchar ();
        while ( ch > '9' || ch < '0' ) { if ( ch == '-' ) w = -1; ch = getchar ();}
        while ( ch >='0' && ch <='9' ) { s = s * 10 + ch - '0'; ch = getchar();}
        return s * w;
    }
    void add(int a,int b,Edge edge[],int &e_num){
        edge[e_num].s=a; 
        edge[e_num].e=b; 
        edge[e_num].next=head[a]; 
        head[a]=e_num++;
        return;
    }
    void tarjan(int x){
        int j;
        tim[x]=low[x]=++vis_num;
        instack[x]=1;
        st.push(x);
        for(j=head[x];j!=-1;j=edge1[j].next){
            int u=edge1[j].e;
            if(tim[u]==-1){
                tarjan(u);
                if(low[x]>low[u])low[x]=low[u];
            }
            else if(instack[u] && low[x]>tim[u])low[x]=tim[u];
        }
        if(low[x]==tim[x]){
            cnt++;
            do{
                j=st.top();
                st.pop();
                instack[j]=0;
                belong[j]=cnt;
            }while(j!=x);
        } 
        return;
    }
    
    int topo(){
        int i,cur,u,count,num;
        count=0;
        for(i=1;i<=cnt;i++){
            if(de[i]==0){
                cur=i;count++;
            }
        }
        if(count>1)return 0;
        num=cnt;
        while(num--){
            count=0;
            for(i=head[cur];i!=-1;i=edge2[i].next){
                u=edge2[i].e;
                de[u]--;
                if(de[u]==0){
                    count++;cur=u;
                }
            }
            if(count>1)return 0;
        }
        return 1;
    }
    
    void solve(){
        int i;
        cnt=vis_num=0;
        memset(instack,0,sizeof(instack));
        memset(low,0,sizeof(low));
        memset(tim,-1,sizeof(tim));
        for(i=1;i<=n;i++){
            if(tim[i]==-1)
                tarjan(i);
        }
        e_num2=0;
        memset(head,-1,sizeof(head));
        memset(de,0,sizeof(de));
        for(i=0;i<e_num1;i++){
            int j=edge1[i].s;
            int k=edge1[i].e;
            if(belong[j]!=belong[k]){
                add(belong[j],belong[k],edge2,e_num2);
                de[belong[k]]++;
            }
        }
        if ( topo() == 1 ) {
            puts ("Yes");
            return;
        }
        else puts("No");
        return;
    }
    
    int main( void ){
        freopen ( "game.in" , "r" , stdin );
        freopen ( "game.out" , "w" , stdout );
        int t;
        scanf("%d",&t);
        while(t--){
            int a,b;
            n = Read();
            m = Read();
            e_num1=0;
            memset(head,-1,sizeof(head));
            while(m--){
                a = Read();
                b = Read();
                add(a,b,edge1,e_num1);
            }
            solve();
        }
        return 0;
    }
    

    $ T3 $ . (我们仍未知道我们那天所见过的花的名字):

    吐槽时间:这真的不是 $ lxl $ 出的题 $ QAQ $

    我估计这道题唯一的坑点就是误导一些 $ dalao $ 写带修主席树了

    对于 $ 30 $ 分的数据,我们直接暴力模拟就好了。

    对于 $ 60 $ 分的数据,我本来没想开这么大的,但是不然就有常数优化大师可以暴力碾标算了。这60分是给莫队的分数,其实也算是给常数写大了的同学们的。(莫队讲起来太麻烦,就不讲了QAQ)
    对于 $ 100 $ 分的数据,我们可以发发现数据范围下边有这样一行人畜无害的小字:
    对于所有的数据,数据保证不同的k的个数不超过10个

    emmmmm....看到这一句话应该就知道正解绝对不会是主席树了。

    首先考虑操作一:维护区间最小值 $ + $ 边界插入。大家应该都会QWQ。。
    (动态开点不会的话。。。。。)告诉我我再讲一下吧

    然后就是操作二: 维护每个区间内有多少数的小于这个数。嗯,主席树板子(逃

    那我给泥萌那个提示干嘛啊。。。。。

    其实,因为 $ k $ 的个数很小,所以我们直接可以考虑建立 $ k $ 的个数棵线段树,每个线段树维护离散化之后相应的那个k值,然后区间求和。

    维护的话,因为只修改边界,而且是单点修改,所以直接动态开点的方法修改就好了。

    没了

    代码:

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #define LC ( ( root ) << 1 )
    #define RC ( ( root ) << 1 | 1 )
    
    using namespace std;
    
    const int N = 2e5 + 10;
    
    int n , q , cnt1 , cnt2;
    int num[N];
    struct Que {
        int sign;
        int left;
        int right;
        int k;
    }que[N];
    struct Tree {
        int size;
        int val;
    }tree[N << 3][12];
    map < int , bool > mp;
    map < int , int > mp2;
    map < int , int > mp3;
    
    inline int read () {
        int s = 0 , w = 1;
        char ch = getchar ();
        while ( ch > '9' || ch < '0' ) { if ( ch == '-' ) w = -1; ch = getchar ();}
        while ( ch >= '0' && ch <= '9' ) { s = s * 10 + ch - '0'; ch = getchar ();}
        return s * w; 
    }
    inline int min ( int x , int y ) {
        return x < y ? x : y;
    }
    void Build1 ( int root , int start , int end ) {
        tree[root][0].size = end - start + 1;
        if ( start == end ) {
            tree[root][0].val = num[start];
            return;
        }
        int mid = ( ( start + end ) >> 1 );
        Build1 ( LC , start , mid );
        Build1 ( RC , mid + 1 , end );
        tree[root][0].val = min ( tree[LC][0].val , tree[RC][0].val );
        return;
    }
    void Build2 ( int root , int start , int end , int sign , int kkk ) {
        tree[root][sign].size = end - start + 1;
        if ( start == end ) {
            tree[root][sign].val = ( kkk <= num[start] ) ? 1 : 0;
            return;
        }
        int mid = ( ( start + end ) >> 1 );
        Build2 ( LC , start , mid , sign , kkk );
        Build2 ( RC , mid + 1 , end , sign , kkk );
        tree[root][sign].val = tree[LC][sign].val + tree[RC][sign].val;
        return;
    }
    void update ( int root , int nstart , int nend , int qstart , int qend , int sign , int addval ) {
        if ( qstart > nend || qend < nstart ) 
            return;
        if ( qstart == nstart && qend == nend ) {
            if ( !sign ) {
                tree[root][0].val = addval;
                num[nstart] = addval;
            }
            else {
                if ( tree[root][0].val >= mp3[sign] )
                    tree[root][sign].val = 1;
            }
            return;
        }
        int mid = ( ( nstart + nend ) >> 1 );
        update ( LC , nstart , mid , qstart , qend , sign , addval );
        update ( RC , mid + 1 , nend , qstart , qend , sign , addval );
        if ( !sign ) 
            tree[root][0].val = min ( tree[LC][0].val , tree[RC][0].val );
        else 
            tree[root][sign].val = tree[LC][sign].val + tree[RC][sign].val;
        return;
    }
    int check ( int root , int nstart , int nend , int qstart , int qend , int sign ) {
        if ( qstart > nend || qend < nstart ) {
            if ( !sign ) return 0x3f3f3f3f;
            else  return 0;
        }
        if ( qstart <= nstart && qend >= nend ) 
        	return tree[root][sign].val;
        int mid = ( ( nstart + nend ) >> 1 );
        if ( !sign )
            return min ( check ( LC , nstart , mid , qstart , qend , sign ) , check ( RC , mid + 1 , nend , qstart , qend , sign ) );
        else 
            return check ( LC , nstart , mid , qstart , qend , sign ) + check ( RC , mid + 1 , nend , qstart , qend , sign );
    }
    
    int main ( void ) {
    	freopen ( "question.in" , "r" , stdin );
       freopen ( "question.out" , "w" , stdout );
        memset ( num , 0x3f3f3f3f , sizeof ( num ) );
        n = read () , q = read ();
        for ( int i = 1 ; i <= n ; i++ ){
            num[i] = read ();
        }
        Build1 ( 1 , 1 , n + q + 1 );
        for ( int i = 1 ; i <= q ; i++ ) {
            que[i].sign = read ();
            if ( que[i].sign == 1 ) {
                que[i].left = read ();
                que[i].right = read ();
                continue;
            }
            else if ( que[i].sign == 2 ) {
                que[i].left = read ();
                que[i].right = read ();
                que[i].k = read ();
                if ( !mp[que[i].k] ) {
                    cnt1++;
                    mp[que[i].k] = 1;
                    mp2[que[i].k] = cnt1;
                    mp3[cnt1] = que[i].k;
                    Build2 ( 1 , 1 , n + q + 1 , cnt1 , que[i].k );
                }
            } 
        }
        int now_right = n;
        for ( int i = 1 ; i <= q ; i++ ) {
            int opts = que[i].sign;
            if ( opts == 1 ) {
                int l = que[i].left;
                int r = que[i].right;
                int ans = check ( 1 , 1 , n + q + 1 , l , r , 0 );
                printf ( "%d
    " , ans );
                now_right++;
                for ( int j = 0 ; j <= cnt1 ; j++ ) 
                    update ( 1 , 1 , n + q + 1 , now_right , now_right , j , ans );
                // for ( int rr = 1 ; rr <= now_right ; rr++ )
                // 	cout << check ( 1 , 1 , n + q + 1 , rr , rr , 0 )<< " ";
                // cout << endl;
            }
            else {
                int l = que[i].left;
                int r = que[i].right;
                int kkkk = que[i].k;
                int ans = check ( 1 , 1 , n + q + 1 , l , r , mp2[kkkk] );
                printf ( "%d
    " , ans );
                now_right++;
                for ( int j = 0 ; j <= cnt1 ; j++ ) 
                    update ( 1 , 1 , n + q + 1 , now_right , now_right , j , ans );
                // for ( int rr = 1 ; rr <= now_right ; rr++ )
                // 	cout << check ( 1 , 1 , n + q + 1 , rr , rr , 0 )<< " ";
                // cout << endl;
            }
        }
        return 0;
    }
    

    三道题讲完了,我感觉我还是不毒瘤的吧,,,

    题目挺简单的QWQ

  • 相关阅读:
    Centos下Oracle11gR2安装教程与自动化配置脚本
    你知道CPU结构也会影响Redis性能吗?
    谈谈InnoDB中的B+树索引
    理论:第十一章:大厂程序员如何使用GitHub快速开发学习
    理论:第十四章:生产环境服务器变慢如何诊断,性能评估
    理论:第十三章:堆溢出,栈溢出的出现场景以及解决方案
    理论:第十二章:Dubbo的运行原理,支持什么协议,与SpringCould相比它为什么效率要高一些,Zookeeper底层原理
    理论:第十章:公平锁,非公平锁,可重入锁,递归锁,自旋锁,读写锁,悲观锁,乐观锁,行锁,表锁,死锁,分布式锁,线程同步锁分别是什么?
    理论:第九章:JVM内存模型,算法,垃圾回收器,调优,四大引用,常见的JVM错误,类加载机制(双亲委派),创建一个对象,这个对象在内存中是怎么分配的?
    理论:第八章:线程是什么,有几种实现方式,它们之间的区别是什么,线程池实现原理,JUC并发包,ThreadLocal与Lock和Synchronize区别
  • 原文地址:https://www.cnblogs.com/Repulser/p/9612515.html
Copyright © 2020-2023  润新知