2013 Asia Regional Changchun

Find_Girl_Firend的第二次训练


http://acm.hdu.edu.cn/search.php?field=problem&key=2013+Asia+Regional+Changchun+&source=1&searchmode=source

hdu_4813 hdu_4815 hdu_4819 hdu_4821


A Hard Code


题意

不是我敲的。题目意思好像是把一个字符串分成 N 份长度为M的子串吧?GT手速慢,被他妹子强了FB。233333

code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
int t;
string s;

int main()
{
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        cin>>s;
        int cnt=0;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                cout<<s[cnt++];
            }
            cout<<endl;
        }
    }
    return 0;
}

C Little Tiger vs. Deep Monkey


题意

N 道题目,每道题目分值为ai,答对得分,答错不得分。Monkey每次都是随机猜答案,所以每题答对的概率为 0.5 。问Tiger至少要得多少分才能使自己不输掉比赛的概率至少是p。

GT一直没给我翻对题目意思。后来自己默默的看了几遍。然后去拿外卖的时候把思路想通了。回来就A了。不过还是手残Wa了一发。

思路

思路比较简单,求出Monkey每种得分的概率。然后确定一个最小的 m 使得[0m]的得分的概率和 sp
而每种概率的得分是个dp。
dp[i][j]表示前i题得分为j的概率。

dp[i][j]={dp[i1][j]×0.5dp[i1][ja[i]]×0.5+dp[i1][j]×0.5if(j<a[i])if(ja[i])

code

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

int T, n;
double p;
int a[42];

double dp[42][40 * 1000 + 2];

int sum = 0;

int main () {
    scanf ("%d", &T);
    for (int _case = 1; _case <= T; _case++) {
        scanf ("%d%lf", &n, &p);

        sum = 0;
        for (int i=1; i<=n; i++) {
            scanf ("%d", &a[i]);
            sum += a[i];
        }
        memset(dp, 0, sizeof(dp));
        dp[0][0] = 1;
        for (int i=1; i<=n; i++) {
            for (int j=0; j<=sum; j++) {
                if (j >= a[i]) dp[i][j] = dp[i-1][j] * 0.5 + dp[i-1][j-a[i]] * 0.5;
                else dp[i][j] = dp[i-1][j] * 0.5;
            }
        }

        double _s = 0.0;
        int ans = -1;
        for (int i=0; i<=sum; i++) {
            _s += dp[n][i];
            if (_s >= p) {
                ans = i;
                break;
            }
        }
        printf ("%d\n", ans);
    }
    return 0;
}

G Mosaic


题意

一个 n×n 的矩阵。每次 q 个查询,x,y,c。以 (x,y) 为中心, c 为边长的矩形可以包括的矩阵中的元素的最大值和最小值。然后把(x, y)点的值更新为(maxval+minval2)

思路

膜拜学弟啊。线段树套线段树。或者叫二维线段树吧?裸的。

code

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

const int MAXN = 800;

const int INF = 999999999;

int n, q;

int sg_max[MAXN<<2][MAXN<<2];
int sg_min[MAXN<<2][MAXN<<2];

// int _cnt = 0;

void create_y(int lx, int rx, int lrx, int ly, int ry, int lry) {

    if (ly == ry) {
        if (lx == rx) {
            int tmp;
            scanf ("%d", &tmp);
            // _cnt ++;
            sg_max[lrx][lry] = sg_min[lrx][lry] = tmp;

        } else {

            sg_max[lrx][lry] = max(sg_max[lrx << 1][lry], sg_max[lrx << 1 | 1][lry]);
            sg_min[lrx][lry] = min(sg_min[lrx << 1][lry], sg_min[lrx << 1 | 1][lry]);
        }
        return ;
    }

    int m = (ly + ry) / 2;

    create_y(lx, rx, lrx, ly, m, lry<<1);
    create_y(lx, rx, lrx, m+1, ry, lry<<1|1);

    sg_max[lrx][lry] = max(sg_max[lrx][lry << 1], sg_max[lrx][lry << 1 | 1]);
    sg_min[lrx][lry] = min(sg_min[lrx][lry << 1], sg_min[lrx][lry << 1 | 1]);

}

void create_x(int lx, int rx, int lrx) {
    if (lx == rx) {
        create_y(lx, rx, lrx, 1, n, 1);
        return ;
    }

    int m = (lx + rx) / 2;

    create_x(lx, m, lrx<<1);
    create_x(m+1, rx, lrx<<1|1);

    create_y(lx, rx, lrx, 1, n, 1);
}


void update_y(int lx, int rx, int lrx, int ly, int ry, int lry, int _x, int _y, int _s) {
    if (ly == ry ) {
        if (lx == rx) {
            sg_max[lrx][lry] = sg_min[lrx][lry] = _s;
        } else {
            sg_max[lrx][lry] = max(sg_max[lrx << 1][lry], sg_max[lrx << 1 | 1][lry]);
            sg_min[lrx][lry] = min(sg_min[lrx << 1][lry], sg_min[lrx << 1 | 1][lry]);
        }
        return ;
    }

    int m = (ly + ry) / 2;

    if (_y <= m) update_y(lx, rx, lrx, ly, m, lry << 1, _x, _y, _s);
    if (_y >  m) update_y(lx, rx, lrx, m+1, ry, lry << 1 | 1, _x, _y, _s);

    sg_max[lrx][lry] = max(sg_max[lrx][lry << 1], sg_max[lrx][lry << 1 | 1]);
    sg_min[lrx][lry] = min(sg_min[lrx][lry << 1], sg_min[lrx][lry << 1 | 1]);

}

void update_x(int lx, int rx, int lrx, int _x, int _y, int _s) {
    if (lx == rx && rx == _x) {

        update_y(lx, rx, lrx, 1, n, 1, _x, _y, _s);
        return ;
    }

    int m = (lx + rx) / 2;

    if (_x <= m) update_x(lx, m, lrx << 1, _x, _y, _s);  
    if (_x >  m) update_x(m+1, rx, lrx << 1 | 1, _x, _y, _s);

    update_y(lx, rx, lrx, 1, n, 1, _x, _y, _s); 
}

int max_val, min_val;

void query_y(int lx, int rx, int lrx, int ly, int ry, int lry, int Lx, int Rx, int Ly, int Ry) {
    if (Ly <= ly && ry <= Ry) {
        max_val = max(max_val, sg_max[lrx][lry]);
        min_val = min(min_val, sg_min[lrx][lry]);

        return ;
    } 

    int m = (ly + ry) / 2;

    if (Ly <= m) query_y(lx, rx, lrx, ly, m, lry << 1, Lx, Rx, Ly, Ry);
    if (Ry >  m) query_y(lx, rx, lrx, m+1, ry, lry << 1 | 1, Lx, Rx, Ly, Ry);

}


void query_x (int lx, int rx, int lrx, int Lx, int Rx, int Ly, int Ry) {

    if (Lx <= lx && rx <= Rx) {
        query_y(lx, rx, lrx, 1, n, 1, Lx, Rx, Ly, Ry);
        return ;
    }

    int m = (lx + rx) / 2;

    if (Lx <= m) query_x(lx, m, lrx << 1, Lx, Rx, Ly, Ry);
    if (Rx >  m) query_x(m+1, rx, lrx << 1 | 1, Lx, Rx, Ly, Ry);
}


int main () {

    int T;
    scanf ("%d", &T);
    for (int cases = 1; cases <= T; cases++) {
        scanf ("%d", &n);
        create_x(1, n, 1);
        // cout << "_cnt: " << _cnt << endl;
        scanf ("%d", &q);

        int tmp_x, tmp_y, tmp_l;
        int Lx, Rx, Ly, Ry, S;

        printf("Case #%d:\n", cases);

        for (int i=0; i<q; i++) {
            scanf ("%d%d%d", &tmp_x, &tmp_y, &tmp_l);

            Lx = (tmp_x - tmp_l / 2) >  0 ? tmp_x - tmp_l / 2 : 1;
            Rx = (tmp_x + tmp_l / 2) <= n ? tmp_x + tmp_l / 2 : n;
            Ly = (tmp_y - tmp_l / 2) >  0 ? tmp_y - tmp_l / 2 : 1;
            Ry = (tmp_y + tmp_l / 2) <= n ? tmp_y + tmp_l / 2 : n;

            // cout << " -> " << Lx << " " << Rx << " " << Ly << " " << Ry << endl;

            max_val = -INF;
            min_val = INF;

            query_x(1, n, 1, Lx, Rx, Ly, Ry);

            // cout << "maxval :" << max_val << endl;
            // cout << "minval :" << min_val << endl;

            S = (max_val + min_val) / 2;

            update_x(1, n, 1, tmp_x, tmp_y, S);

            printf ("%d\n", S);
        }
    }
    return 0;
}

I String


题意

统计给定字符串 S 有多少个是”recoverable”串的子串。”recoverable”串定义为长度等于M×L,并且可分成连续的M个长度为L的子串。这M个子串不重复。

思路

确实想了好久,然而大神当年打这套现场赛的时候早就AC了。首先得得到这个字符串的所有的长度为L的子串的 hash 值。map就再见了。GT不造哪里学来的黑科技得出了这些子串的 hash 值。

然后枚举串的起点 l(0l<L) ,对该起点可以找到 M 个连续的长度为L的子串。这里可以用map对这M个子串的 hash 值来判断是否出现重复。无重复则 cnt++ 。然后可以删除头上的长度为 L 的子串,并在后面添加长尾L的子串。同样用map判重。同样无重复则 cnt++

数据水了,GT强走了我的FB。也怪我手残写出一句,没有1A。

code

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
typedef unsigned long long  ull;
using namespace std;
const int maxn=100010;
const ull seed=31;
char str[100010];
ull h[maxn];
ull _hash[maxn];
ull base[maxn];

void init() {
    base[0]=1;
    for(int i=1;i<maxn;i++) {
        base[i]=base[i-1]*seed;
    }
}

int m, l;

map<ull, int> mp;

int main () {

    init();
    for (; scanf ("%d%d", &m, &l) == 2; ) {
        scanf ("%s", str);

        int len = strlen(str);
        h[len]=0;
        for(int i=len-1;i>=0;i--) {
            h[i]=h[i+1]*seed+str[i]-'a'+1;
        }

        for (int i=0; i<len; i++) {
            _hash[i]=h[i]-h[i+l]*base[l];
            // cout << _hash[i] << " ";
        }// cout << endl;

        int ans = 0;
        int L = l;
        for (int i=0; i<L; i++) {
            mp.clear();
            int _cnt = 0;

            int _l = i;
            int _r = i;
            for (int j=0; j<m; j++) {
                if (mp[_hash[_r]] == 1) _cnt++;
                mp[_hash[_r]] ++;
                _r += L;
            }

//            cout << "i " << i << " _l: " << _l << " _r " <<  _r << endl;
            if (_cnt == 0) ans++;

            while (_r < len && _r + L -1 < len) {
                if (mp[_hash[_r]] == 1) _cnt++;
                mp[_hash[_r]]++;

                if (mp[_hash[_l]] == 2) _cnt--;
                mp[_hash[_l]]--;

                _r += L;
                _l += L;
                if (_cnt == 0) ans++;
            }

        }
        cout << ans << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值