2018中国大学生程序设计竞赛 - 网络选拔赛1001 贪心 1003数学 1004费马大定理+奇偶数列法则 1009 排列组合 1010树状数组维护dp

版权声明:本文为博主原创文章,未经博主允许也可以转载。 https://blog.csdn.net/FrankAx/article/details/82181258

1001
题意:给一些城市的买卖价格,要求选择买或者卖一个或者不买不卖,问最后获得的最大利润。
思路:贪心。set维护最小堆,最小的价格小于当前的就可以卖了获得利润,不过这题可以反悔,就是说如果已经卖了这件物品,后面碰到获得更大利润的城市,需要反悔再卖,所以加上标记,如果是直接买的就次数加一并且利润加,如果是交换过了就不加次数,保证次数最小,要确定好优先级保证同等加个交换过的大于买的。
Code:

#include <bits/stdc++.h>
#define LL long long 
#define mp make_pair
using namespace std;
typedef pair<LL,int> P;
int main(){
    int T; 
    int n ; 
    int num ; 
    multiset<P>s;
    scanf("%d",&T);
    while( T-- ){
        LL x ; 
        s.clear();
        LL res = 0LL;
        num = 0 ;
        scanf("%d",&n);
        multiset<P>::iterator it ;
        for( int i = 0 ; i < n ; i++ ){
            scanf("%lld",&x);
            if( s.size() ){
                it = s.begin();
                if( (*it).first < x ){
                    res += ( x - (*it).first );
                    if( (*it).second ){
                        num ++;
                    }
                    s.erase(it);
                    s.insert(mp(x,0));
                    s.insert(mp(x,1));
                }else{
                    s.insert(mp(x,1));
                }
            }else{
                s.insert(mp(x,1));
            }
        }
        printf("%lld %d\n",res,num<<1);
    }
    return 0 ; 
}

1003
题意:要求定义+和*运算,使得(m+n)^p = m ^ p + n ^ p,p为素数。
还要满足题中给定的集合相等的约束。
思路:取模运算。
这里写图片描述
Code:

#include <bits/stdc++.h>
using namespace std;

#define LL long long 
const int AX = 1e5+666;
int main(){
    ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int T ;
    int n ;
    cin >> T;
    while( T-- ){
        cin >> n ; 
        for( int i = 0 ; i < n ; i ++ ){
            cout << i ; 
            for( int j = 1 ; j < n ; j ++ )
                cout << ' ' << ( i + j ) % n ; 
            cout << endl;
        }
        for( int i = 0 ; i < n ; i++ ){
            cout << 0 ;
            for( int j = 1 ; j < n ; j ++ )
                cout << ' ' << ( i * j ) % n ; 
            cout << endl;
        }
    }
    return 0;
}

1004
题意:
思路:费马大定理:n > 2 时,等式无解。
奇偶数列法则
如a^2+b^2=c^2是直角三角形的三个整数边长,则必有如下a值的奇数列、偶数列关系成立;
(一) 直角三角形a^2+b^2=c^2奇数列a法则:
若a表为2n+1型奇数(n=1、2、3 …), 则a为奇数列平方整数解的关系是:
a=2n+1
b= n^2+(n+1)^2-1
c= n^2+(n+1)^2
(二) 直角三角形a^2+b^2=c^2的偶数列a法则:
若a表为2n型偶数(n=2、3、4…), 则a为偶数列平方整数解的关系是:
a= 2n
b= n^2 -1
c= n^2+1
Code:

#include <bits/stdc++.h>
using namespace std;
#define LL long long 
const int AX = 1e5 + 66 ;
int main(){
    int T;
    LL n , a  ;
    scanf("%d",&T);
    while( T -- ){
        scanf("%lld%lld",&n,&a);
        if( !n || n > 2 ) {
            printf("-1 -1\n");
        }else{
            if( n == 1 ){
                printf("1 %lld\n",a+1);
            }
            else if( n == 2 ) {
                if( a & 1 ){
                    LL tmp = a / 2 ;
                    LL b = 2 * tmp * tmp + 2 * tmp;
                    LL c = 2 * tmp * tmp + 2 * tmp + 1 ; 
                    printf("%lld %lld\n",b,c);
                }
                else{
                    LL tmp = a / 2 ;
                    LL b = tmp * tmp - 1;
                    LL c = tmp * tmp + 1;
                    printf("%lld %lld\n",b,c);
                }
            }
        }
    }
    return 0;
}

1009
题意:1-n的排列有n!种,给出n-1条边为两点的权值。求所有排列构成所有图的和。
思路:对于每一条边,要经过该边,x,y一定在该边的左右两侧,设左边为m个点,右边为n-m个。
所有排列的情况则为:2* 左边点个数右边点个数权值除了这条边外点的排列边数
2*m*(n-m)w(n-2)!*(n-1)
Code:

#include <bits/stdc++.h>
#define pb push_back
#define LL long long
using namespace std;
const int AX = 1e5+66;
const int MOD = 1e9+7;
struct Node{
    int  v , w ; 
};
LL fac[AX];
LL res ;
LL num[AX];
int n ;
std::vector<Node> G[AX];
void dfs( int x , int pre ){
    num[x] = 1 ;
    for( int i = 0 ; i < G[x].size() ; i++ ){
        int v = G[x][i].v ;
        int w = G[x][i].w ;
        if( v == pre ) continue;
        dfs( v , x ) ;
        num[x] += num[v];
        res += ( 1LL * num[v] * ( n - num[v] ) % MOD * w % MOD );
    }
}

void init(){
    fac[0] = 1 ; 
    for( int i = 1 ; i < AX ; i++ ){
        fac[i] = 1LL * i * fac[i-1] % MOD;
    }
}

int main(){
    init();
    while( ~scanf("%d",&n) ){
        res = 0LL;
        for( int i = 0 ; i <= n ; i++ ){
            G[i].clear();
            num[i] = 0 ; 
        }
        int x , y , v ; 
        for( int i = 1 ; i < n ; i ++ ){
            scanf("%d%d%d",&x,&y,&v);
            G[x].pb((Node){y,v});
            G[y].pb((Node){x,v});
        }
        dfs( 1 , 0 ) ;
        printf("%lld\n",2LL*res%MOD*fac[n-1]%MOD);
    }
    return 0 ; 
}

1010
题意:给n个村庄,只能向上向右向右下走,只能右下方向进入村庄,进入村庄会给一定价值,问从0,0到1e9,1e9,能够获得的最大价值。
思路:可以得到dp转移方程:
dp[i][j] = max( dp[i-1][j-1] , dp[i-1][j] , dp[i][j-1] ) + v[i][j]
可以用树状数组维护前缀的最大值优化dp
注意的是1e9过大,需要将纵坐标离散化。
Code:

#include <bits/stdc++.h>
#pragma comment(linker, “/STACK:1024000000,1024000000”)
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int AX = 1e5+66; 
int a[AX]; 
std::vector<int> v;
struct Node{
    int x , y , v ; 
    bool operator < (const Node &z) const{
        return ( ( x < z.x ) || ( x == z.x && y > z.y ) );
    }
}G[AX];
int n ;
int getid( int x ){
    return lower_bound( v.begin() , v.end() , x ) - v.begin() + 1 ; 
}
int lowbit( int x ){
    return ( x & (-x) );
}
int getsum( int x ){
    int res = 0 ; 
    while( x ){
        res = max( res , a[x] );
        x -= lowbit(x);
    }
    return res ; 
}
void update( int site , int v ){
    while( site < AX ){
        a[site] = max( a[site] , v );
        site += lowbit(site);
    }
}
int main(){ 
    int T ;
    scanf("%d",&T);
    while( T-- ){
        scanf("%d",&n);
        memset( a, 0 , sizeof(a) ); 
        for( int i = 0 ; i < n ; i ++ ){
            scanf("%d%d%d",&G[i].x,&G[i].y,&G[i].v); 
            v.push_back(G[i].y);
        }
        sort( G , G + n );
        sort( v.begin() , v.end() );
        v.erase( unique( v.begin() , v.end() ) , v.end() ) ;
        int res = 0 ;
        for( int i = 0 ; i < n ; i++ ){
            if( !G[i].x || !G[i].y ) continue;
            int idx = getid( G[i].y );  
            int ans = getsum( idx - 1 );
            res = max( res , G[i].v + ans );
            update( idx , G[i].v + ans );
        }
        printf("%d\n",res);
    }
    return 0 ;
}

猜你喜欢

转载自blog.csdn.net/FrankAx/article/details/82181258