zoukankan      html  css  js  c++  java
  • 2018 东北地区大学生程序设计竞赛(ABEHIK)

    HDU6500:Problem A. Game with string

    题意:

      给你一个字符串s以及它的m个子串的首尾位置,现在Alice和 Bob两个人轮流在任一子串的前面或者后面加1个字符,要求加了这个串加了一个字符之后仍然是s的子串,谁不能加了谁就输了,要你输出谁赢。

    题解:

      每个子串可以加的字符次数是恒定的:s串的长度-子串的长度。那么我们将所有子串可以加的次数加起来再判断奇偶就能得出答案。

      傻逼多组WA了几发

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 100000+10;
    const int INF = 1e9+10;
    const ll mod = 998244353;
    int main() {
        string s;
        while (cin>>s){
            int len = s.length();
            int n,l,r,sum = 0;
            scanf("%d",&n);
            for (int i = 0; i < n; i++){
                scanf("%d%d",&l,&r);
                sum += len - (r-l+1);
            }
            if (sum&1) printf("Alice
    ");
            else printf("Bob
    ");
        }
        return 0;
    }
    View Code

    HDU6501:Problem B. Memory Banks

    题意:

      有60种不同种类的内存存储区,编号为0~59,第i种内存存储区的内存大小为2i,告诉你每种内存存储区的数量。

      有n个空间站,每个空间站需要wi的内存空间,每个空间站你都要用你已有的内存存储区来为它提供正好wi的内存空间。

      如果有空间站不能正好有wi的内存空间输出-1,否则输出你剩下的内存存储区的总存储量。

    题解:

      要使组成的空间站尽可能多,我们需要先取容量大的。我们可以把每个站需要的内存空间转化为2进制,从高位到低位,如果这i位为1就代表需要1个容量为2i的内存存储区,如果少了可以用2倍的容量为2i-1的内存存储区代替。

      例如如果需要10的内存空间,化成2进制就是1010,需要1个23和1个21,若没有容量为23的可以用两个容量为22的代替。

      如果当前空间站内存不够,则输出-1,否则求各个类型剩余容量与个数的乘积之和。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 100000+10;
    const int INF = 1e9+10;
    const ll mod = 1e9+7;
    ll qp(ll a, ll b){
        ll ans = 1;
        while (b) {
            if (b&1) ans = (ans * a) % mod;
            a = (a * a) % mod;
            b >>= 1;
        }
        return ans;
    }
    ll a[70];
    int main() {
        while (~scanf("%lld",&a[0])) {
            for (int i = 1; i < 60; i++) scanf("%lld",&a[i]);
            int n;
            scanf("%d",&n);
            bool fg = 1;
            while (n--) {
                ll w,sum = 0;
                scanf("%lld",&w);
                int cnt = 0,b[70];
                while (w) {
                    b[cnt++] = w%2;
                    w>>=1;
                }
                for (int i = cnt - 1; i >= 0; i--) {
                    sum = sum * 2 + b[i];
                    if (!a[i]) continue;
                    if ( sum > a[i]) {
                        sum -= a[i];
                        a[i] = 0;
                    } else {
                        a[i] -= sum;
                        sum = 0;
                    }
                }
                if (sum) fg = 0;
            }
            if (!fg) printf("-1
    ");
            else {
                ll ans = 0;
                for (int i = 0; i < 60; i++) {
                    if (a[i]) ans = (ans + (a[i]%mod) * qp(2,i) % mod )%mod;
                }
                printf("%lld
    ",ans);
            }
        }
        return 0;
    }
    View Code

    HDU6504:Problem E. Split The Tree

    题意:

      给你一颗节点由1到n编号的树,告诉你每个点的值Wi 。将树的权重定义为树中 不同的节点的值Wi 的数量。

      删掉一条边之后这棵树就变成了两棵树,得分是两颗数的权重和,要你求一棵树拆成两棵树的最大权重和。

    题解:

      我们可以通过dfs序将这棵树 变成一个线性的,且每个子树在一段连续区间。求树的权重就相当于求一段区间内不同值的数量。

      要求删掉一条边之后形成的两棵树的最大权重和。我们可以枚举删每一条边时的权重和,

      在每一次计算的时候,我们可以用树状数组维护,将区间扩大一倍,如果删掉边之后一个子树的区间范围为[l,r] ,那么另一个子树区间为[r+1,n+l-1]。计算这两个区间不同节点值数量和即可。

      这题也可以用莫队,还没写,待补。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 200000 +10;
    const int INF = 1e9+10;
    const ll mod = 1e9+7;
    struct node{
        int id,l,r;
        node() {}
        node(int id,int l,int r):id(id),l(l),r(r) {}
    } q[N];
    int n,dfsnum;
    int sum[N], val[N], L[N], R[N], vis[N], ans[N], num[N];
    vector<int> edge[N];
    bool cmp(node x,node y) {
        if (x.r != y.r) return x.r < y.r;
        else return x.l < y.l;
    }
    int lowbit(int x) {
        return x&(-x);
    }
    void add(int x,int k) {
        while (x <= n*2) {
            sum[x]+=k;
            x+=lowbit(x);
        }
    }
    int query(int x) {
        int ans = 0;
        while (x) {
            ans += sum[x];
            x -=lowbit(x);
        }
        return ans;
    }
    void dfs(int x) {
        L[x] = ++dfsnum;
        num[dfsnum] = num[dfsnum+n] = x;
        for (int i = 0; i < edge[x].size(); i++) {
            dfs(edge[x][i]);
        }
        R[x] = dfsnum;
    }
    int main() {
        while(~scanf("%d",&n)) {
            for (int i = 0; i <= n; ++i) {
                edge[i].clear();
            }
            for (int i = 2; i <= n; i++) {
                int u;
                scanf("%d",&u);
                edge[u].push_back(i);
            }
            dfsnum = 0;
            dfs(1);
            for (int i = 1; i <= n; i++) {
                scanf("%d",&val[i]);
                val[n+i] = val[i];
            }
            int cnt = 0;
            for (int i = 1; i <= n; i++) {
                q[++cnt] = node(i,L[i],R[i]);
                q[++cnt] = node(i,R[i] + 1, n+L[i]-1);
            }
            sort(q+1,q+1+cnt,cmp);
            int maxx = 0, top = 1;
            memset(vis,0, sizeof(vis));
            memset(ans,0, sizeof(ans));
            memset(sum,0,sizeof(sum));
            for (int i  = 1; i <= cnt; i++) {
                for (int j = top; j <= q[i].r; ++j) {
                    int x = val[num[j]];
                    if (vis[x]) add(vis[x],-1);
                    vis[x] = j;
                    add(vis[x],1);
                }
                top = q[i].r+1;
                ans[q[i].id] += query(q[i].r) - query(q[i].l - 1);
                maxx = max(maxx,ans[q[i].id]);
            }
            printf("%d
    ",maxx);
        }
        return 0;
    }
    树状数组

    HDU6507:Problem H. Store The Matrix

    题意:

      给你一个r*c的矩阵M,它可以分解成多个矩阵相乘:M = A1×A2 · · ·×An (n≥1),每个矩阵Ai的大小为ri*ci。我们通过存这个n个矩阵的元素来存矩阵M,每个矩阵Ai的元素个数为ri*ci,求最少需要存的元素数量。

    题解:

      这题我的理解是:对于一个矩阵M,你要不就不拆,n=1,存的元素数量为r*c。要不就拆成两个矩阵相乘,我们知道要得到r*c的矩阵,需要两个大小分别为r*x,x*c的矩阵相乘,显然当x为矩阵M的秩时最优。

      所以这是一个求矩阵的秩的模板题。

      这个题还可以用高斯消元写,待补。

      参考博客:https://www.cnblogs.com/letlifestop/p/10819422.html

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 50+10;
    const int INF = 1e9+10;
    const ll mod = 1e9+7;
    int a[N][N];
    int n,m;
    int r() {
        int i=0,j=0,k,r,u;
        while(i<n&&j<m)
        {
            r=i;
            for(k=i; k<m; k++)
            {
                if(a[k][j])
                {
                    r=k;
                    break;
                }
            }
            if(a[r][j])
            {
                if(r!=i)
                {
                    for(k=0; k<=n; k++)
                    {
                        swap(a[r][k],a[i][k]);
                    }
                }
                for(u=i+1; u<m; u++)
                {
                    if(a[u][j])
                    {
                        for(k=i; k<=n; k++)
                        {
                            a[u][k]^=a[i][k];
                        }
                    }
                }
                ++i;
            }
            j++;
        }
        return i;
    }
    int main() {
        while(~scanf("%d%d",&n,&m)) {
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= m; j++){
                    scanf("%d",&a[i][j]);
                }
            }
            printf("%d
    ",min(n*m,max(1,r())*(n+m)));
        }
        return 0;
    }
    View Code

     HDU6508:Problem I. Spell Boost

    题意:

      你有n张牌,每张牌需要wi点法力,能给敌人造成xi点伤害。卡牌有两种类型,一种是魔法牌,一种是增幅牌。一张牌可能包含这两种类型。每当你使用一张魔法牌的时候,对于每一张未被使用的增幅牌i需要的法力值wi减1。现在你有W点法力,问能造成的最大的伤害值为多少。

    题解:

      因为魔法牌能降低增幅牌所需的法力值,所以我们可以先按需要值从小到大取魔法牌,然后在从小到大取增幅牌。每件物品只有一件,容量为W,你可以取或者不取,使伤害值最大。类似于背包问题,不过这里的法力值是会减少的。我们可以用dp[i][j][k] 来表示造成的伤害值,i为第i张牌,j为前面使用了多少张增幅牌,k为用了的法力值。因为我们每次选第i张牌都是在前i-1张牌选了之后操作的,我们可以把数组简化成dp[i%2][j][j],节省空间。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 500+10;
    const int INF = 1e9+10;
    const ll mod = 1e9+7;
    struct node{
        int w,x,is1,is2;
    }a[N];
    int dp[2][N][N];
    bool cmp(node i, node j) {
        if (i.is1 != j.is1) return i.is1 > j.is1;
        if (i.is2 != j.is2) return i.is2 < j.is2;
        return i.w < j.w;
    }
    int main() {
        int n,m;
        while(~scanf("%d%d",&n,&m)) {
            memset(dp,-1,sizeof(dp));
            for (int i = 1; i <= n; i++) {
                scanf("%d%d%d%d",&a[i].w,&a[i].x,&a[i].is1,&a[i].is2);
            }
            sort(a+1,a+n+1,cmp);
            dp[0][0][0]=0;
            for (int i = 1; i <= n; i++) {
                memset(dp[i%2],-1,sizeof(dp[i%2]));
                for (int j = 0; j <= i; j++) {
                    for (int k = 0; k <= m; k++) {
                        if (dp[(i - 1) % 2][j][k] == -1) continue;
                        dp[i % 2][j][k] = max(dp[i % 2][j][k], dp[(i - 1) % 2][j][k]);
                        int u = j + a[i].is1; //判断是不是魔法牌
                        int v = k + max(0, a[i].w - j * a[i].is2);//减之前判断需不需要减
                        if (v <= m) {
                            dp[i % 2][u][v] = max(dp[i % 2][u][v], dp[(i - 1) % 2][j][k] + a[i].x);
                        }
                    }
                }
            }
            int ans = 0;
            for (int i = 0; i <=n; i++) {
                for (int j = 0; j<= m; j++)
                    ans = max(ans,dp[n%2][i][j]);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    HDU6510:Problem K. Harbin Sausage

    题意:

      对于下面这个三视图,给你H和R,每单位体积需要花费 3/Pi(圆周率) 问这个几何体花费的总金额。

      

    题解:

      公式为:(4*Pi*R*R*R/3 + Pi*R*R*H) * 3/Pi = 4*R*R*R+3*R*R*H

    代码: 

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 100000+10;
    const int INF = 1e9+10;
    const ll mod = 998244353;
    int main() {
        int h,r;
        scanf("%d%d",&h,&r);
        printf("%d",4*r*r*r+3*r*r*h);
        return 0;
    }
    View Code
  • 相关阅读:
    Vue 计算属性(四)
    Vue 方法与事件(三)
    Vue 基本指令使用(二)
    Vue 项目开发环境搭建(一)
    SpringBoot 整合 Dubbo
    Nginx 中 include 指令使用
    Nginx 中 root 和 alias 的使用区别
    JS动态修改网站图标以及标题
    vue中使用轮播图插件carousel,克隆的图片点击事件无效的解决办法
    根据 url + fileName下载文件,并更改文件名
  • 原文地址:https://www.cnblogs.com/l999q/p/10860602.html
Copyright © 2011-2022 走看看