zoukankan      html  css  js  c++  java
  • Luogu 2671 求和 NOIP2015T3

    题目链接

    题解

    20pts

    $O(n^3)$枚举$x,y,z$,根据题目要求判断

    40pts

    $O(n^2)$枚举$x,z$,需要满足$x,z$奇偶相同

    20~40pts的代码我都没有写过...就不贴了

    70~90pts

    尝试对40pts的暴力进行优化

    题目对三元组的两个限制我们在40pts的时候已经用来优化过了,还有一个限制是颜色相同

    我们可以以颜色为关键字对数组进行排序,对每个数算答案的时候,只需要枚举相同颜色的这一段即可(因为三元组要求有序,所以要从$x+2$开始枚举)

    这样的复杂度是$O(n*cnt_{col})$(这里的$cnt_{col}$为出现次数最多的颜色的出现次数)

    使用$scanf$将会得到70pts

    使用快读或$scanf+O2$将会得到80pts

    使用快读+$O2$将会得到90pts

    ($fread$在这里的效果和快读是差不多的,因为数只有$1e5$个)

    #include <bits/stdc++.h>
    
    #define ll long long
    #define inf 0x3f3f3f3f
    #define il inline
    
    namespace io {
    
        #define in(a) a=read()
        #define out(a) write(a)
        #define outn(a) out(a),putchar('
    ')
    
        #define I_int int
        inline I_int read() {
            I_int x = 0 , f = 1 ; char c = getchar() ;
            while( c < '0' || c > '9' ) { if( c == '-' ) f = -1 ; c = getchar() ; }
            while( c >= '0' && c <= '9' ) { x = x * 10 + c - '0' ; c = getchar() ; }
            return x * f ;
        }
        char F[ 200 ] ;
        inline void write( I_int x ) {
            I_int tmp = x > 0 ? x : -x ;
            if( x < 0 ) putchar( '-' ) ;
            int cnt = 0 ;
            while( tmp > 0 ) {
                F[ cnt ++ ] = tmp % 10 + '0' ;
                tmp /= 10 ;
            }
            while( cnt > 0 ) putchar( F[ -- cnt ] ) ;
        }
        #undef I_int
    
    }
    using namespace io ;
    
    using namespace std ;
    
    #define N 100010
    const int mod = 10007 ;
    
    int n = read() , m = read() ;
    struct node {
        int col , val , id ;
    } a[ N ] ;
    
    bool cmp( node a , node b ) {
        return a.col < b.col ;
    }
    
    int main() {
        for( int i = 1 ; i <= n ; i ++ ) a[ i ].val = read() , a[ i ].id = i ;
        for( int i = 1 ; i <= n ; i ++ ) a[ i ].col = read() ;
        sort( a + 1 , a + n + 1 , cmp ) ;
        int cur = 0 ;
        ll ans = 0 ;
        for( int i = 1 ; i <= n ; i ++ ) {
            ll sum = 0 ;
            for( cur = i + 1 ; a[ i ].col == a[ cur ].col && cur <= n ; cur ++ ) {
                if( ( a[ i ].id + a[ cur ].id ) % 2 == 0 ) 
                    sum = ( sum + ( 1ll * ( a[ i ].id + a[ cur ].id ) % mod * 1ll * ( a[ i ].val + a[ cur ].val ) % mod ) % mod  ) % mod ;
            } 
            ans = ( ans + sum ) % mod ;
        }
        printf( "%lld
    " , ( ans + mod ) % mod ) ;
        return 0 ;
    }

    100pts

    考虑使用数学方法优化以上做法

    我们现在有什么条件呢,列举一下

    1.$x$和$z$的奇偶性相同且颜色相同

    2.求和公式为$(x+z)(num_x+num_z)$

    从求和公式入手,把括号拆掉,式子变成$x*num_x+x*num_z+z*num_x+z*num_z$

    设$x1,x2,x3$的奇偶性相同且颜色相同(那么他们组成的二元组就等同于符合条件的三元组)

    考虑$x1$对答案的贡献:

    对于$(x1,x2)$,$x1$的贡献为$x1*num_{x1}+x1*num_{x2}$

    对于$(x1,x3)$,$x1$的贡献为$x1*num_{x1}+x1*num_{x3}$

    那么$x_1$对答案的贡献就是

    $x1*(num_{x2}+num_{x3})+2*x1*num_{x1}$

    然后多加入一个数$x4$也可以得到类似的贡献(多代几个也就看出来规律了)

    推广到$x_n$结论也是一样的

    结论:

    设$s=sum num_{xi}$(这里的$xi$均满足条件1)$cnt=cnt_{col}$,$cnt_{col}$为当前颜色奇偶相同的数的个数

    则$xi$对答案的贡献为$xi*(s-num_{xi})+(cnt-1)*xi*num_{xi}$($cnt$要$-1$,因为$xi$不能和自己组成二元组)

    所以将$s$和$cnt$统计出来就行了,注意要分奇偶统计

    复杂度$O(n)$

    #include <bits/stdc++.h>
    
    #define ll long long
    #define inf 0x3f3f3f3f
    #define il inline
    #define int long long
    
    namespace io {
    
        #define in(a) a=read()
        #define out(a) write(a)
        #define outn(a) out(a),putchar('
    ')
    
        #define I_int int
        inline I_int read() {
            I_int x = 0 , f = 1 ; char c = getchar() ;
            while( c < '0' || c > '9' ) { if( c == '-' ) f = -1 ; c = getchar() ; }
            while( c >= '0' && c <= '9' ) { x = x * 10 + c - '0' ; c = getchar() ; }
            return x * f ;
        }
        char F[ 200 ] ;
        inline void write( I_int x ) {
            if( x == 0 ) { putchar( '0' ) ; return ; }
            I_int tmp = x > 0 ? x : -x ;
            if( x < 0 ) putchar( '-' ) ;
            int cnt = 0 ;
            while( tmp > 0 ) {
                F[ cnt ++ ] = tmp % 10 + '0' ;
                tmp /= 10 ;
            }
            while( cnt > 0 ) putchar( F[ -- cnt ] ) ;
        }
        #undef I_int
    
    }
    using namespace io ;
    
    using namespace std ;
    
    #define N 100010
    const int mod = 10007 ;
    
    int n , m ;
    struct node {
        int col , val ;
    } a[ N ] ;
    int cnt[ N ][ 2 ] , sum[ N ][ 2 ] ;
    
    signed main() {
        n = read() , m = read() ;
        for( int i = 1 ; i <= n ; i ++ ) a[ i ].val = read() ;
        for( int i = 1 ; i <= n ; i ++ ) a[ i ].col = read() ;
        for( int i = 1 ; i <= n ; i ++ ) {
            cnt[ a[ i ].col ][ i&1 ] ++ ;
            sum[ a[ i ].col ][ i&1 ] = ( sum[ a[ i ].col ][ i&1 ] + a[ i ].val ) % mod ;
        }
        ll ans = 0 ;
        for( int i = 1 ; i <= n ; i ++ ) {
            ll num = cnt[ a[ i ].col ][ i&1 ] , s = sum[ a[ i ].col ][ i&1 ] ;
            ans = ( ans + ( i*(s-a[i].val) + (num-1)*a[i].val*i ) % mod ) % mod ;
        }
        printf( "%lld
    " , ans % mod ) ;
        return 0 ;
    }
  • 相关阅读:
    Python Twisted系列教程8:使用Deferred的诗歌下载客户端
    Python Twisted系列教程7:小插曲,Deferred
    Python Twisted系列教程6:抽象地利用Twisted
    Python Twisted系列教程5:由Twisted支持的诗歌客户端
    Python Twisted系列教程4:由Twisted支持的诗歌客户端
    Python Twisted系列教程2:异步编程初探与reactor模式
    多线程--future模式初体验
    【java工具类】生成二维码
    Maven手动命令行导入ojdbc6
    【javascript】生成二维码
  • 原文地址:https://www.cnblogs.com/henry-1202/p/9926290.html
Copyright © 2011-2022 走看看