2014 北京邀请赛ABDHJ题解

A. A Matrix

点击打开链接

构造,结论是从第一行开始往下产生一条曲线,使得这条区间最长且从上到下递减,

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <stdio.h>
#include <vector>
#include <set>
using namespace std;
#define N 100005
vector<int>G[N], P[N], tmp;
set<int>s[N];
set<int>::iterator it;
int n,m;
bool work(){
    for(int i = m; i>1; i--) {
        for(int j = G[i].size()-1; j>=0; j--) {
            it = s[i-1].lower_bound(-G[i][j]);
            if(it==s[i-1].end())return false;
            int pos = lower_bound(G[i-1].begin(), G[i-1].end(), -(*it))-G[i-1].begin();
            P[i-1][pos] = j;
            s[i-1].erase(it);
        }
    }
    return true;
}
void init(){
    for(int i = 0; i <= n; i++)G[i].clear(), s[i].clear(), P[i].clear();
}
int Stack[N];
int main(){
    int T, Cas = 1,i,j,k;cin>>T;
    while(T--) {
        init();
        scanf("%d %d",&n,&m);
        bool success = true;
        for(i=1;i<=m;i++){
            scanf("%d",&k);
            for(int z = 0; z < k; z++)
            {
                scanf("%d",&j);
                G[i].push_back(j);
                s[i].insert(-j);
                if(z && G[i][z-1]>G[i][z])
                    success=false;
                P[i].push_back(-1);
            }
        }
        printf("Case #%d: ",Cas++);
        if(success && work()) {
            int top = 0;
            for(i = 0; i < P[1].size(); i++)
            {
                int h = 1, l = i;
                tmp.clear();
                while(1)
                {
                    tmp.push_back(G[h][l]);
                    if(P[h][l]==-1)break;
                    l = P[h][l];
                    h++;
                }
                for(j=tmp.size()-1;j>=0;j--)
                    Stack[top++] = tmp[j];
            }
            for(i=0;i<top;i++)
            printf("%d%c",Stack[i],i==top-1?'\n':' ');
        }
        else puts("No solution");
    }
    return 0;
}

B. Beautiful Garden

B:点击打开链接

暴力

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long ll;
const int N = 42;
int n, a[N];
int dis[N * N], dep;
bool vis[N][N];
int main() {
    int T;
    scanf("%d", &T);
    for (int cas = 1; cas <= T; ++cas) {
        scanf("%d", &n);
        for (int i = 0; i < n; ++i)
            scanf("%d", &a[i]);
        std::sort(a, a + n);
        dep = 0;
        for (int i = 0; i < n; ++i)
            for (int j = i + 1; j < n; ++j)
                dis[dep++] = a[j] - a[i];
        std::sort(dis, dis + dep);
        dep = std::unique(dis, dis + dep) - dis;

        int ans = n - 1, cnt, idx, f;
        ll st;

        for (int i = 0; i < dep; ++i) {
            memset(vis, 0, sizeof vis);
            for (int k = 0; k < n; ++k)
                for (int z = 0; z < n; ++z)
                    if(!vis[k][z]) {
                        st = a[k] - (ll)z * dis[i];
                        cnt = idx = 0;
                        f = 1;
                        for (int l = 0; l < n; ++l) {
                            while (idx < n && a[idx] < st)
                                ++idx;
                            if (idx < n && st == a[idx]) {
                                if (vis[idx][l]) {
                                    f = 0;
                                    break;
                                }
                                vis[idx][l] = true;
                                ++cnt, ++idx;
                            }
                            st += dis[i];
                        }
                        if (f && n - cnt < ans)
                            ans = n - cnt;
                    }
        }
        printf("Case #%d: %d\n", cas, ans);
    }

    return 0;
}

E. Elegant String

E:点击打开链接

先得到一个dp方程

dp[i][j]表示字符串长度为i,结尾有j个数互不相同的方法数

然后得到转移方程再用矩阵快速幂加速

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <stdio.h>
#include <vector>
#include <set>
using namespace std;
#define ll long long
#define Matr 11
#define mod 20140518
struct mat{
    ll a[Matr][Matr],size;
    mat(){
        size = 0;
        memset(a, 0, sizeof a);
    }
};
mat multi(mat m1,mat m2){
    mat ans = mat(); ans.size = m1.size;
    for(int i = 1; i <= m1.size; i++)
        for(int j = 1; j<= m2.size; j++)
            if(m1.a[i][j])
                for(int k = 1; k <= m1.size; k++)
                    ans.a[i][k] = (ans.a[i][k]+m1.a[i][j]*m2.a[j][k])%mod;
    return ans;
}
mat quickmulti(mat m,ll n){
    mat ans = mat();
    ll i;
    for(i=1;i<=m.size;i++)ans.a[i][i] = 1;
    ans.size = m.size;
    while(n){
        if(n&1)ans = multi(m,ans);
        m=multi(m,m);
        n /= 2;
    }
    return ans;
}
ll n,k;
int main(){
    ll T, Cas = 1;cin>>T;
    while(T--){
        cin>>n>>k;
        mat z = mat();
        for(ll i = 1; i <= k; i++)
            for(ll j = i; j <= k; j++)
                z.a[i][j] = 1;
        ll now = k;
        for(ll i = 2; i <= k; i++, now--)
            z.a[i][i-1]+=now;
        z.size = k;
        z = quickmulti(z, n-1);
        ll tmp = 0;
        for(ll i = 1; i <= k; i++)
            tmp += z.a[i][1];
        tmp *= (k+1);
        tmp %= mod;
        printf("Case #%lld: %lld\n",Cas++,tmp);
    }
    return 0;
}

H. Happy Reversal

H:点击打开链接

把所有数字取法后都一起排序,最大的减最小的即可

可能最大最小都来源一个数,则答案就是 第二大减最小 或者最大减第二小

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 20005;
ll a[N], b[N];
ll er[N];
int main() {
    int T;
    char s[66];
    er[0] = 1;
    for(int i = 1;i<63;i++)er[i] = er[i-1]*2;
    while(~scanf("%d", &T)) {
        for(int cas = 1; cas <= T; cas ++) {
            int n, m;
            scanf("%d%d", &n, &m);
            for(int i = 0; i < n; i ++) {
                scanf("%s", s);
                ll suma = 0;
                ll sumb = 0;
                for(int j = 0; j < m; j ++) {
                    suma = suma * 2 + (s[j] == '1');
                    sumb = sumb * 2 + (s[j] == '0');
                }
                a[i*2] = max(suma, sumb);
                a[i*2+1] = min(suma, sumb);
            }
            sort(a, a + n + n);
            ll ans;
            if( a[2*n-1] + a[0] + 1 == er[m] ) ans = max(a[2*n-2] - a[0], a[2*n-1] - a[1]);
            else ans = a[2*n-1] - a[0];
            printf("Case #%d: %lld\n", cas, ans);
        }
    }
    return 0;
}

J. Justice String

J:点击打开链接

hash二分第一个不同的字符距离0的位置,再二分第二个不同的字符距离第一个字符的位置

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX_N = 3000007;
int sa[MAX_N], ws[MAX_N], rank[MAX_N], height[MAX_N];
#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
int wa[MAX_N],wb[MAX_N],wv[MAX_N],wss[MAX_N];
struct suffix {
    int c0(int *r, int a, int b) {
     return r[a] == r[b] && r[a+1] == r[b+1] && r[a+2] == r[b+2];
    }
    int c12(int k,int *r,int a,int b) {
       if(k == 2)
        return r[a] < r[b] || ( r[a] == r[b] && c12(1,r,a+1,b+1) );
      else return r[a] < r[b] || ( r[a] == r[b] && wv[a+1] < wv[b+1] );
    }
    void sort(int *r,int *a,int *b,int n,int m)    {
        int i;
        for(i = 0;i < n;i++)wv[i] = r[a[i]];
        for(i = 0;i < m;i++)wss[i] = 0;
        for(i = 0;i < n;i++)wss[wv[i]]++;
        for(i = 1;i < m;i++)wss[i] += wss[i-1];
        for(i = n-1;i >= 0;i--)
        b[--wss[wv[i]]] = a[i];
    }
    void dc3(int *r,int *sa,int n,int m) {
        int i, j, *rn = r + n;
        int *san = sa + n, ta = 0, tb = (n+1)/3, tbc = 0, p;
        r[n] = r[n+1] = 0;
        for(i = 0;i < n;i++)if(i %3 != 0)wa[tbc++] = i;
        sort(r + 2, wa, wb, tbc, m);
        sort(r + 1, wb, wa, tbc, m);
        sort(r, wa, wb, tbc, m);
        for(p = 1, rn[F(wb[0])] = 0, i = 1;i < tbc;i++)
        rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p - 1 : p++;
        if(p < tbc)dc3(rn,san,tbc,p);
        else for(i = 0;i < tbc;i++)san[rn[i]] = i;
        for(i = 0;i < tbc;i++) if(san[i] < tb)wb[ta++] = san[i] * 3;
        if(n % 3 == 1)wb[ta++] = n - 1;
        sort(r, wb, wa, ta, m);
        for(i = 0;i < tbc;i++)wv[wb[i] = G(san[i])] = i;
        for(i = 0, j = 0, p = 0;i < ta && j < tbc;p++)
        sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++];
        for(;i < ta;p++)sa[p] = wa[i++];
        for(;j < tbc;p++)sa[p] = wb[j++];
    }
    void DA(int str[],int sa[],int n,int m)    {
        for(int i = n;i < n*3;i++)
            str[i] = 0;
        dc3(str, sa, n+1, m);
        int i,j,k = 0;
        for(i = 0;i <= n;i++)rank[sa[i]] = i;
        for(i = 0;i < n; i++)
        {
            if(k) k--;
            j = sa[rank[i]-1];
            while(str[i+k] == str[j+k]) k++;
            height[rank[i]] = k;
        }
    }
};
int RMQ[MAX_N], mm[MAX_N], best[20][MAX_N];
void initRMQ(int n) {
    mm[0] = -1;
    for(int i = 1; i <= n; ++i) {
        mm[i]=((i & (i - 1)) == 0) ? mm[i - 1] + 1 : mm[i - 1];
    }
    for (int i = 1; i <= n; ++i) {
        best[0][i] = i;
    }
    for (int i = 1; i <= mm[n]; ++i) {
        for (int j = 1; j + (1 << i) - 1 <= n; ++j) {
            int a = best[i - 1][j];
            int b = best[i - 1][j + (1 << (i - 1))];
            if (RMQ[a] < RMQ[b]) best[i][j] = a;
            else best[i][j] = b;
        }
    }
}
int query(int a, int b) {
    int t = mm[b - a + 1];
    b -= (1 << t) - 1;
    a = best[t][a], b = best[t][b];
    return RMQ[a] < RMQ[b] ? a : b;
}
int lcp(int a, int b) {
    a = rank[a], b = rank[b];
    if (a > b) swap(a, b);
    return height[query(a + 1, b)];
}
char A[MAX_N],B[MAX_N];
int r[MAX_N], da[MAX_N];
int main() {
    int T;
    int cas = 0;
    scanf("%d",&T);
    while(T-- > 0) {
        suffix ar;
        scanf("%s%s",A, B);
        int len1 = strlen(A);
        int len2 = strlen(B);
        if(len1 < len2) {
            printf("Case #%d: -1\n", ++cas);
            continue;
        }
        int n = len1 + len2 + 1;
        for(int i = 0; i < len1; ++i) r[i] = A[i];
        for(int i = 0; i < len2; ++i) r[len1 + 1 + i] = B[i];
        r[len1] = 1;
        r[n] = 0;
        ar.DA(r, sa, n, 128);

        for(int i = 1; i <= n; ++i)
          RMQ[i] = height[i];
        initRMQ(n);
        int ans = -1;
        for(int i = 0; i <= len1 - len2; ++i) {
            int st = i;
            int ed = len1 + 1;
            int tmp = lcp(st, ed);
        //    printf("here1 %d %d %d\n", st, ed, tmp);
            st += tmp;
            ed += tmp;
            if(ed >= n) {
                ans = i;
                break;
            }
            st++;
            ed++;
            if(ed >= n) {
                ans = i;
                break;
            }
            tmp = lcp(st, ed);
        //    printf("here2 %d %d %d\n", st, ed, tmp);
            st += tmp;
            ed += tmp;
            if(ed >= n) {
                ans = i;
                break;
            }
            st++;
            ed++;
            if(ed >= n) {
                ans = i;
                break;
            }
            tmp = lcp(st, ed);
    //        printf("here3 %d %d %d\n", st, ed, tmp);
            st += tmp;
            ed += tmp;
            if(ed >= n)  {
                ans = i;
                break;
            }
        }
        printf("Case #%d: %d\n", ++cas, ans);
    }
    return 0;
}

2014 北京邀请赛ABDHJ题解,布布扣,bubuko.com

时间: 2024-09-30 07:07:01

2014 北京邀请赛ABDHJ题解的相关文章

2014北京邀请赛(部分题解)

马上要去比赛了. 今天做了一下2014北京邀请赛,出了两道题目,感觉很水啊... 首先H题: H. Happy Reversal Time Limit: 1000ms Case Time Limit: 1000ms Memory Limit: 65536KB 64-bit integer IO format: %lld      Java class name: Main Submit Status PID: 34988 Font Size:  +   - Elfness is studying

BNUOJ 34985 Elegant String 2014北京邀请赛E题 动态规划 矩阵快速幂

Elegant String Time Limit: 1000msMemory Limit: 65536KB 64-bit integer IO format: %lld      Java class name: Main We define a kind of strings as elegant string: among all the substrings of an elegant string, none of them is a permutation of "0, 1,-, k

ACM-ICPC 2014北京邀请赛 H Happy Reverse [模拟]

题意:给出n个二进制串,可以把其中的一些0和1反转(即0变1,1变0),找出转化后n个串中的最大值和最小值的差值. 分析:思路就是把所有的串和反转的存在一个数组中,然后排序,找最大值和最小值的差,(如果是同一个串反转的就找第二大的和最小的或第二小和最大的中的最大值).注意假如只有一个串的话结果为0 DEBUG: 这题写了好久 1.第一次用vim,很爽,但是还没熟练 2.忽视了这题的范围,显然要用longlong 3.用了longlong后还WA,用脚本跑出来数据发现在longlong下,min的

2014北京邀请赛 Happy Reversal

H. Happy Reversal 64-bit integer IO format: %lld      Java class name: Main Elfness is studying in an operation "NOT". For a binary number A, if we do operation "NOT A", after that, all digits of A will be reversed. (e.g. A=1001101, af

BNUOJ 34985 Elegant String 2014北京邀请赛E题 矩阵快速幂

题目链接:http://acm.bnu.edu.cn/bnuoj/problem_show.php?pid=34985 题目大意:问n长度的串用0~k的数字去填,有多少个串保证任意子串中不包含0~k的某一个全排列 邀请赛上A的较多的一道题,比赛的时候死活想不出,回来之后突然就想通了,简直..... = =! 解题思路: 对于所有串我们都只考虑末尾最多有多少位能构成全排列的一部分(用l来表示),即最多有多少位不重复的数字出现,将问题转化为求末尾最多有k位能构成全排列的串的总数量 假设k为5,有一个

2014北京邀请赛E题-矩阵快速幂

题意:长度为n(1<=n<=10^18)的并且任意连续子串都不是0-k(1<=k<=9)的一个排列的字符串有多少种. 解法:矩阵快速幂.dp[i][j]表示i长度最后连续j个不同(即最后j个无重复,最后j+1个有重复)的字符串的个数.状态选好很重要.设计状态时最重要考虑是唯一性和可传递性,比赛时明明知道肯定是矩阵快速幂,但是一直没想到这个状态表示,自己设计的自己都不会转移. dp[i][j]有了后,后边加一个字符,这个字符可以是j之内的任意一个,也可以是j以外的,这样枚举每种情况,

hihocoder 1084 扩展KMP &amp;&amp; 2014 北京邀请赛 Justice String

hihocoder 1084 : http://hihocoder.com/problemset/problem/1084 北京邀请赛 Just  String http://www.bnuoj.com/v3/problem_show.php?pid=34990 两道题同样的做法,题目基本内容是找到A的字串中和B串长度一样,且不同的字符个数不超过k个的置. 以hihocoder 1084为例, 是求有多少个A的字串的,与B串长度一样,且不同的字符个数不超过k. 分析:预处理hash,然后对每个字

2014北京邀请赛反思

北京嘛,我大天朝之帝都,当然是高手云集撒. 躺了21个小时的火车,历史以来最久了.旅社住"7天",一直以为"7天"是为情侣们准备的,事实估摸着也是这样.我哩个擦,厕所门不能锁,小小脑补了一下,顿时邪恶万分... 张逗彪找gf去了,被梁平君吼了,搞得我拒绝了同学周六早上带我逛北京的邀请.算了躺床睡觉. 开幕式,看到了会讲笑话的董适,果然是会讲段子!知道了他们信科院就有3个院士,呵呵,湖大总共几个院士? 热身赛,真忧伤!题目改了,没看到,一直在想tm别人能在1-50(实

2014北京邀请赛 F Football on Table

题目来源: http://acm.bnu.edu.cn/bnuoj/problem_show.php?pid=34986 题意: 一个人在玩桌面足球,有m行球员,每行球员有ai个,给出每个球员的宽度和相邻球员之间的距离,球从最左边射出,给出球的起点坐标跟方向向量,问能够到达最右边的概率. 思路:球员的相对位置固定,球员可以移动一定的距离.计算球经过球员的概率, 用1 - 球经过球员的概率 即为 可以穿过的概率. 枚举一遍所有行. 代码如下: const int Max_N = 105 ; dou