BC #41

2015-05-18 20:40:13

总结:比赛中搞了两题。。。赛后 A 题被逗比地 FST 了... 

  后来发现真的是打逗比了... TAT,赛后补到 C 题。

 

A题 hdu 5228:

  题意:给出5张牌,问将其变为同花顺至少需要换多少张牌(同花顺是指花色相同,且连号,注意:10,11,12,13,1 属于连号,但 11,12,13,1,2 不是)

  思路:用 vis[][] 标记各个花色是否出现,然后用 n^2 枚举同花顺起点,每个起点开始找5张牌,记录已经出现的牌数 cnt,统计出 cnt 的最大值 cntmax,答案就是 5 - cntmax

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define getmid(l,r) ((l) + ((r) - (l)) / 2)
#define MP(a,b) make_pair(a,b)
#define PB(a) push_back(a)

typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int INF = (1 << 30) - 1;

int T;
char s[10];
int vis[4][15];

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        memset(vis,0,sizeof(vis));
        for(int i = 1; i <= 5; ++i){
            scanf("%s",s);
            int a = s[0] - 'A',b = 0;
            int len = strlen(s);
            for(int j = 1; j < len; ++j) b = b * 10 + s[j] - '0';
            vis[a][b] = 1;
        }
        int tmax = 0;
        for(int i = 0; i < 4; ++i){
            for(int j = 1; j <= 9; ++j){
                int cnt = 0;
                for(int k = j; k <= j + 4; ++k) cnt += vis[i][k];
                tmax = max(tmax,cnt);
            }
            int cnt = 0;
            for(int k = 10; k <= 13; ++k) cnt += vis[i][k];
            cnt += vis[i][1];
            tmax = max(tmax,cnt);
        }
        printf("%d\n",5 - tmax);
    }
    return 0;
}
View Code

 

B题 hdu 5229:

  题意:有 n 个串,两人博弈,每次等概率选择任意两串,A 先后 B 后手,每次每人能有两种操作:

  (1)选一个字符串删掉最后个字符。(2)若两串相同,清空两个字符串。不能操作的人输。问 A 赢的概率。

  思路:如果两串的长度和奇数,那么 A 只要保持过程中两串长度不等就必胜(这样一轮两人只能去掉2个,A必取最后个)。当然如果两串本来就相同也是 A 赢。

       如果两串长度和为偶数,那么 B 只要保持过程中两串长度不等,就必胜。

     所以我们要做的事就很简单了,统计串长度为奇数 / 偶数的串数,以及相等串的数量。然后做简单运算即可,考虑用 map。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define getmid(l,r) ((l) + ((r) - (l)) / 2)
#define MP(a,b) make_pair(a,b)
#define PB(a) push_back(a)

typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int INF = (1 << 30) - 1;

int T;
int N;
map<string,int> mp;
string s;

int Gcd(int a,int b){
    while(a > 0 && b > 0)
        if(a > b) a %= b;
        else b %= a;
    return a + b;
}

int main(){
    scanf("%d",&T);
    while(T--){
        mp.clear();
        int odd = 0,even = 0,tmp = 0;
        scanf("%d",&N);
        for(int i = 1; i <= N; ++i){
            cin >> s;
            mp[s]++;
            if(s.length() & 1) odd++;
            else even++;
        }
        map<string,int>::iterator it;
        for(it = mp.begin(); it != mp.end(); it++){
            int v = (*it).second;
            if(v > 1) tmp += v * (v - 1) / 2;
        }
        int up = odd * even + tmp;
        int down = N * (N - 1) / 2;
        int g = Gcd(up,down);
        printf("%d/%d\n",up / g,down / g);
    }
    return 0;
}
View Code

 

C题 hdu 5230:

  题意:在1~N-1中若干个不重复的数,使得他们的和在 [L,R] 内。其中 0<=L<=R<N , N<=1e5

  思路:首先暴力 dp 可以实现 n^2 的做法,仔细一下,因为数不重复,所以取到几百个数后他们的和就会比1e5大了,所以能取的数并不会很多。

  挖掘出这个隐含条件后,dp 的复杂度就降为 n*sqrt(n) 了(类似需要挖掘条件从而缩小范围的题目以前 cf 出过,#286 div2 的 C 题,2014网络赛也见过)

  dp 的转移方程比较巧妙,来自题解:设 dp[i][j] 表示当前已经选了最大的 i 个想选的数,和为 j 的方案数。转移时有两种情况:

  (1)把之前选择的数全部加1,但是选的数的数量不增加。

  (2)把之前选择的数全部加1,再加入新的1,选的数的数量加1。

  这种 “位移” 式的统计方法相当巧妙。比赛时只想到了 sqrt(n) 这个点,然而并不会转移。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define getmid(l,r) ((l) + ((r) - (l)) / 2)
#define MP(a,b) make_pair(a,b)
#define PB(a) push_back(a)

typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int INF = (1 << 30) - 1;
const ll mod = 998244353;

int T,N,C,L,R;
ll dp[2][100010],ans;

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d%d",&N,&C,&L,&R);
        L -= C,R -= C;
        int block = (int)sqrt(2.0 * R);
        for(int i = 0; i <= R; ++i) dp[0][i] = 0;
        dp[0][0] = 1;
        ans = 0;
        for(int i = 1; i <= block; ++i){
            int id = i & 1;
            for(int j = 0; j <= R; ++j) dp[id][j] = 0;
            for(int j = i; j <= R; ++j){
                dp[id][j] = (dp[id][j] + dp[id][j - i]) % mod;
                dp[id][j] = (dp[id][j] + dp[id ^ 1][j - i]) % mod;
                if(j >= L) ans = (ans + dp[id][j]) % mod;
            }
        }
        if(L == 0) ans++;
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2015-05-18 22:15  Naturain  阅读(101)  评论(0编辑  收藏  举报