2015 GDUT校赛

周末打了个GDUT的校赛,也是作为SCAU的一场个人排位。

比赛中竟然卡了个特判,1个半钟就切了5条了,然后一直卡。

还有其他两条可以做的题也没法做了,性格太执着对ACM来说也是错呀。

讲回正题 。

A  游戏王 .

目的是集齐6张卡, 然后n个小伙伴手上持有卡num, 给出m种集合 , Stubird需要有某个集合中的卡片才能用c的花费去买这张卡片。

做法是状压dp , 开一个 dp[st] , 表示st( 0 <= st < (1<<6) ) 这个集合最小花费 。

然后开一个邻接链表 g[st] 这样, 存着st这个状态可以去到那些状态 , 费用是多少 。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std ;

typedef long long LL ;
typedef pair<int,int> pii;
#define X first
#define Y second
const int inf = 1e9+7;
const int N = 1<<6 ;

vector<pii>g[N];
LL dp[N] ;

int main () {
    #ifdef LOCAL
        freopen("in.txt","r",stdin);
    #endif // LOCAL
    int _ ; scanf("%d",&_);
    while( _-- ) {

        for( int i = 0 ; i < N ; ++i ) g[i].clear() , dp[i] = inf ;
        int n ; scanf("%d",&n);
        for( int i = 0 ; i < n ; ++i ) {
            int m , num ;
            scanf("%d%d",&m,&num);
            for( int j = 0 ; j < m ; ++j ) {
                int k  ; scanf("%d",&k);
                int st = 0 , vst , c ;
                while( k-- ) {
                    scanf("%d",&vst);
                    st |= (1<<vst) ;
                }
                scanf("%d",&c);
                for( int y = 0 ; y < N ; ++y ) {
                    bool tag = true ;
                    for( int z = 0 ; z < 6 ; ++z ) {
                        if( (st&(1<<z)) && (!(y&(1<<z)))  ) {
                            tag = false ; break ;
                        }
                    }
                    if( tag ) g[y].push_back(pii(num,c));
                }
            }
        }
        dp[0] = 0 ;
        for( int st = 0 ; st < N ; ++st ) {
            for( int i = 0 ; i < g[st].size() ; ++i ) {
                int vst = st | (1<<g[st][i].X) , w = g[st][i].Y ;
                dp[vst] = min( dp[vst] , dp[st] + w ) ;
            }
        }
        if( dp[N-1] == inf )  puts("-1");
        else printf("%d\n",dp[N-1]);
    }
}

/**************************************************************
    Problem: 1116
    User: hl_mark
    Language: C++
    Result: Accepted
    Time:220 ms
    Memory:2324 kb
****************************************************************/

B.完美串

给出一个01串,要该串取反再翻转后与原串相同,至少要多加多少个 0 or 1 。

输入串a后 , 构造一个串b ( a取反再翻转 ) 求它们的最长公共子序列,这里是个dp ..

答案就是 n - dp[n][n] , 首先要证明 n - dp[n][n]  这个答案是无误的 。

要符合条件串长要偶数, 前半段跟后半段的以中线反对称的 。

设 最长公共子序列长度为 x  , 补充 n - x 个 0 , 1 之后必然会符合题目要求,因为添加的时候符合反对称的性质。

那为何是 这个答案是最优? 反证吧。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std ;
const int N = 1010;
int dp[N][N] , a[N] , b[N] ;
char s[N];
int main () {
    #ifdef LOCAL
        freopen("in.txt","r",stdin);
    #endif // LOCAL
    int _ ; scanf("%d",&_);
    while( _-- ) {
        int n ;
        scanf("%d",&n);
        memset( dp , 0, sizeof dp );
        scanf("%s",s);
        for( int i = 0 ; i < n ; ++i ) {
            a[i+1] = s[i] - ‘0‘ ;
        }
        for( int i = n ; i > 0 ; --i ) {
            b[i] = a[n-i+1] ;
            b[i] ^= 1 ;
        }
//        for( int i = 1 ; i <= n ; ++i ) cout << a[i] ; cout <<endl ;
//        for( int i = 1 ; i <= n ; ++i ) cout << b[i] ; cout <<endl ;
        for( int i = 1 ; i <= n ;  ++i ) {
            for( int j = 1 ; j <= n ; ++j ) {
                if( a[i] == b[j] ) dp[i][j] = dp[i-1][j-1] + 1 ;
                else {
                    dp[i][j] = max( dp[i][j-1] , dp[i-1][j] ) ;
                }
            }
        }
        int ans = n ;
        for( int i = 1 ; i <= n ; ++i ) {
            for( int j = 1 ; j <= n ; ++j ) {
                ans = min( ans , n - dp[i][j] );
            }
        }
        printf("%d\n",ans);
    }
}

/**************************************************************
    Problem: 1109
    User: hl_mark
    Language: C++
    Result: Accepted
    Time:384 ms
    Memory:5476 kb
****************************************************************/

C .  GCD = n ,  LCM = m 的对数

其实就是对 n , m 分解之后。 对其不同次幂质因子的分配方案数 。 比赛过程中加了一个错的特判。 搞得一直wa~

#include <cstdio>
#include <iostream>
using namespace std ;
const int N = 100010;
long long fac[N] , cnt[N] , tot ;
void solve( long long x ) {
    for( long long i = 2 ; i * i <= x ; ++i ) if( x % i == 0 ){
        fac[tot] = i ; cnt[tot] = 0 ;
        while( x % i == 0 ) { x /= i ; cnt[tot]++ ; }
        tot++ ;
    }
    if( x != 1 ) { fac[tot] = x ; cnt[tot] = 1 ; tot++ ; }
}
int main () {
    int _ ; scanf("%d",&_);
    while( _-- ) {
        long long n , m ;
        tot = 0 ;
        scanf("%lld%lld",&n,&m);
        if( m % n ) { puts("0"); continue ; }
        solve(n); int c = 0 ;
        for( int i = 0 ; i < tot ; ++i ) if( m % fac[i] == 0 ) {
            int cc = 0 ;
            while( m % fac[i] == 0 ) { m /= fac[i] ; cc++ ;}
            if( cc != cnt[i] ) c++ ;
        }
        tot = 0 ; solve( m ) ; c += tot ;
        long long ans = 1 ;
        for( int i = 0 ; i < c - 1 ; ++i ) ans = ans * 2 ;
        printf("%lld\n",ans);
    }
}

D . 煮菜 , 一分钟可以同时煮 m 个菜 。

ti 为每个菜需要的时间, 若 sum = sigma(ti) ,  总时间 T = sum/m + ( sum % m ==0 ? 0 : 1 )  。

若 T   >  Max ( ti ) .. 是必然能够很配出方案使得时间为T 的 , 否则结果就是 Max(ti) .

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std ;
typedef pair<int,int> pii;
#define X first
#define Y second
const int N = 10010 ;
int main () {
    int _ ; scanf("%d",&_);
    while( _-- ) {
        int sum = 0 , n , m , mx = -1 , x ;
        scanf("%d%d",&n,&m);
        for( int i = 0 ; i < n ; ++i ) {
            scanf("%d",&x);
            mx = max( mx , x );
            sum += x ;
        }
        int t = ( sum / m ) + ( sum % m == 0 ? 0 : 1 ) ;
        int ans = max( mx , t );
        printf("%d\n",ans);
    }
}

E. 强迫症关灯

因为 n , m 只有100,直接暴力, 如果 n , m 达到1e6 的话就线段树吧

#include <cstdio>
#include <cstring>
using namespace std ;
int b[101];
int main () {
    int _ ; scanf("%d",&_);
    while( _-- ) {
        memset( b , 0 , sizeof b );
        int n , m ; scanf("%d%d",&n,&m);
        while( m-- ) {
            int x ; scanf("%d",&x);
            for( int i = x ; i <= n ; ++i ) {
                if( !b[i] ) b[i] = x ;
                else break ;
            }
        }
        printf("%d",b[1]);
        for( int i = 2 ; i <= n ; ++i ) {
            printf(" %d",b[i]);
        }puts("");
    }
}

F.找规律

题目都说了找规律,然后就暴力一下前100个看看规律,然后就可以看出来了

#include <cstdio>
using namespace std ;
int main () {
    int n ;
    while( ~scanf("%d",&n) ) {
        printf("%d\n",( n / 3 * 2 + ( n % 3 > 1 ? 1 : 0 ) ) );
    }
}

/**************************************************************
    Problem: 1122
    User: hl_mark
    Language: C++
    Result: Accepted
    Time:32 ms
    Memory:964 kb
****************************************************************/

G. 用多少条边可以把玩具连起来, 就是求连通分量个数,再-1

写并查集就可以实现了

#include <cstdio>
#include <iostream>
using namespace std ;
const int N = 100010;
int fa[N] ;
bool vis[N] ;
inline int find( int k ) { return fa[k] = ( fa[k] == k ? k : find(fa[k])); }
int main () {
    int _ ; scanf("%d",&_);
    while( _-- ) {
        int n , m ; scanf("%d%d",&n,&m);
        for( int i = 0 ; i <= n ; ++i ) fa[i] = i , vis[i] = false ;
        while( m-- ) {
            int x , y ; scanf("%d%d",&x,&y);
            int fx = find(x) , fy = find(y);
            fa[fy] = fx ;
        }
        int cnt = 0 ;
        for( int i = 1 ; i <= n ; ++i )  {
            int fx = find(i);
            if( !vis[fx] ) { vis[fx] = true ; cnt++; }
        }
        printf("%d\n",cnt-1);
    }
}

/**************************************************************
    Problem: 1118
    User: hl_mark
    Language: C++
    Result: Accepted
    Time:132 ms
    Memory:1972 kb
****************************************************************/

F. 移动2只手指,点音符 。。

简单dp .. dp[i][j][k] 表示点到第i 个音符 , 第一只手指在 j , 第2只手指在 k 的最小花费

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std ;
typedef pair<int,int> pii;
#define X first
#define Y second
const int N = 10010 ;
int dp[N][6][6] , x[N] ;
int main () {
    int _ ; scanf("%d",&_);
    while( _-- ) {
        int n ; scanf("%d",&n);
        for( int i = 1 ; i <= n ; ++i ) scanf("%d",&x[i]);
        memset( dp , 0x3f , sizeof dp );
        int inf = dp[0][0][0] ;
        dp[0][0][0] = 0 ;
        for( int i = 0 ; i < n ; ++i ) {
            for( int j = 0 ; j < 5 ; ++j ) {
                for( int k = 0 ; k < 5 ; ++k ) {
                    if( dp[i][j][k] >= inf ) continue ;
                    dp[i+1][j][ x[i+1] ] = min( dp[i+1][j][ x[i+1] ] , dp[i][j][k] + abs( x[i+1] - k ) );
                    dp[i+1][ x[i+1] ][k] = min( dp[i+1][ x[i+1] ][k] , dp[i][j][k] + abs( x[i+1] - j ) );
                }
            }
        }
        int ans = inf ;
        for( int i = 0 ; i < 5 ; ++i )
            for( int j = 0 ; j < 5 ; ++j )
                ans = min( ans , dp[n][i][j] );
        printf("%d\n",ans);
    }
}

/**************************************************************
    Problem: 1115
    User: hl_mark
    Language: C++
    Result: Accepted
    Time:92 ms
    Memory:2932 kb
****************************************************************/

时间: 2024-12-04 14:37:16

2015 GDUT校赛的相关文章

2015.4 校赛回顾

用了一下午时间重刷了一次校赛题目 不参考资料做的还是2333 第一题手速题 第二题 一开始取余运算少加了一个,WA了一发 #include<iostream> #include<cstdio> #include<cstring> using namespace std; int main() { int i,d[20000]; string c; memset(d,0,sizeof(d)); while(cin>>c) { int n=0; for(i=0;

2015 多校赛 第一场 1007 (hdu 5294)

总算今天静下心来学算法.. Description Innocent Wu follows Dumb Zhang into a ancient tomb. Innocent Wu’s at the entrance of the tomb while Dumb Zhang’s at the end of it. The tomb is made up of many chambers, the total number is N. And there are M channels connect

2015 多校赛 第五场 1010 (hdu 5352)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5352 看题看得心好累. 题目大意: 给出 n 个点,依次执行 m 次操作:输入“1 x”时,表示将与 x 连通的点全部修复:输入“2 x y”,表示在 x 与 y 之间加一条边:输入“3 x y”,表示删除 x 与 y 之间的边.题目确保不会与重边并且操作合法. 题目会给出 k,要求每次修复的的点的数目小于等于k. 问:怎样执行操作1,使得令修复点数最多的同时,令每次执行操作1所修复的点的数目所构成

2015 多校赛 第四场 1010 (hdu 5336)

Problem Description XYZ is playing an interesting game called "drops". It is played on a r∗c grid. Each grid cell is either empty, or occupied by a waterdrop. Each waterdrop has a property "size". The waterdrop cracks when its size is

2015 多校赛 1002 (hdu 5289)

Description Tom owns a company and he is the boss. There are n staffs which are numbered from 1 to n in this company, and every staff has a ability. Now, Tom is going to assign a special task to some staffs who were in the same group. In a group, the

2015 whu校赛f题big data(dp + 小技巧)

题意是给定五个数n(n <= 100),a,b,l,r 另外有函数序列f(x),其中f(x + 1) = f(x) + a或f(x)+ b,f(0) = 0,问有多少个这样的函数序列f(1)到f(n)使得函数序列的和在l和r之间 解题思路如下: 图片有一处错误,要减去的是a*(n + 1) * n而不是 (b - a)* (n + 1) * n,此外,要注意x/c时向上取整和向下取整的问题. 这道题做做停停一个月了今天终于找时间ac了,有点感人呐 代码如下: #include<cstdio&g

2015 多校赛 第四场 1009 (hdu 5335)

Problem Description In an n∗m maze, the right-bottom corner is the exit (position (n,m) is the exit). In every position of this maze, there is either a 0 or a 1 written on it. An explorer gets lost in this grid. His position now is (1,1), and he want

2015 多校赛 第二场 1006 (hdu 5305)

Problem Description There are n people and m pairs of friends. For every pair of friends, they can choose to become online friends (communicating using online applications) or offline friends (mostly using face-to-face communication). However, everyo

2015 多校赛 第二场 1002 (hdu 5301)

Description Your current task is to make a ground plan for a residential building located in HZXJHS. So you must determine a way to split the floor building with walls to make apartments in the shape of a rectangle. Each built wall must be paralled t