2021年广东工业大学第十五届文远知行杯程序设计竞赛

A M形字符串

题目中前缀是M串,前缀二字将题目的难度大大降低了
用字符串hash前缀hash和后缀hash一下,判断两串是否相同。

#include <bits/stdc++.h>

using namespace std;

typedef unsigned long long ULL;

const int N = 200010, base = 131;

char c[N];
int len;
ULL p[N], hl[N], hr[N];

void init()
{
    p[0] = 1;
    for (int i = 1; i <= len; i ++ ) p[i] = p[i - 1] * base;
    for (int i = 1; i <= len; i ++ )
    {
        hl[i] = hl[i - 1] * base + c[i] - 'a' + 1;
    }
    for (int i = len; i >= 1; i -- )
    {
        hr[i] = hr[i + 1] * base + c[i] - 'a' + 1;
    }
}

ULL getl(int l, int r)
{
    return hl[r] - hl[l - 1] * p[r - l + 1];
}

ULL getr(int l, int r)
{
    return hr[l] - hr[r + 1] * p[r - l + 1];
}
bool check(int l, int r)
{
    return getl(l, r) == getr(l, r);
}
int main()
{
      cin >> c + 1;
      len = strlen(c + 1);

      init();

      // for (int i = 1; i <= len; i ++ )
      // {
      //     cout << get(hl, 1, i) << endl;
      // }
      int ans = 0;
      for (int i = 1; i <= len; i ++ )
      {
          // 1~i是回文串
          // cout << getl(1, i) << endl;
          // cout << getr(i, 1) << endl;
          // cout << "---------------------" << endl;
          if (!check(1, i)) continue;
          if (i & 1 && check(1, i / 2 + 1) && check(i / 2 + 1, i)) ans ++;
          else if (i % 2 == 0 && check(1, i / 2) && check(i / 2 + 1, i)) ans ++;
      }

      cout << ans << endl;

      return 0;
}

B 找山坡

单调栈

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <stack>

using namespace std;

const int N = 1000010;

struct Node
{
    int w, id;
};

int n;
int a[N];
stack<Node> stk;

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i ++ )
      scanf("%d", &a[i]);

    int ans = 0;
    for (int i = 1; i <= n; i ++ )
    {
        int x; x = a[i];

        while (stk.size() > 0 && stk.top().w > x) stk.pop();

        if (stk.size() > 0 && stk.top().w == x)
        {
            ans = max(ans, i - stk.top().id);
        }
        else
        {
            stk.push({x, i});
        }
    }

    cout << ans << endl;

    return 0;
}

C 涂墙

求五个数的平方和为n,这五个数都小于1000,不大,而且还是平方和,所以,dfs搜索完全可以

#include <bits/stdc++.h>

using namespace std;

int n;
int path[10];
//u表示使用第几个正方形,val为当前的正方形面积总和
bool dfs(int u, int val, int now)
{
    if (val > n) return false;

    if (u == 5)
    {
        if (val == n)
        {
          // for (int i = 0; i < 5; i ++ )
          //   cout << path[i] << ' ';
          // cout << endl;
          return true;
        }
        else return false;
    }

    for (int i = now; i >= 1; i -- )
    {
        path[u] = i;
        if (dfs(u + 1, val + i * i, i)) return true;
    }

    return false;
}
void solve()
{
    scanf("%d", &n);

    int t = 1000;
    while (t * t >= n) t --;

    memset(path, 0, sizeof path);
    if(dfs(0, 0, t)) puts("YES");
    else puts("NO");
}
int main()
{
    int T;
    cin >> T;

    while (T -- )
    {
        solve();
    }

    return 0;
}

E 捡贝壳

将序列的所有因子都存下
如果当前元素可以被序列元素整除,就把当前元素的下标存进来。
然后,直接通过下标,将l和r找出来

#include <bits/stdc++.h>

using namespace std;

const int N = 100010;

int n, q;
int a[N];
vector<int> v[N];

int main()
{
      scanf("%d%d", &n, &q);
      for (int i = 0; i < n; i ++ )
          scanf("%d", &a[i]);

      for (int i = 0; i < n; i ++ )
      {
          for (int j = 1; j * j <= a[i]; j ++ )
          {
              if (a[i] % j == 0)
              {
                  //j可以被a[i]整除,记录a[i]的下标
                  v[j].push_back(i);
                  if (j != a[i] / j)
                  {
                      v[a[i] / j].push_back(i);
                  }
              }
          }
      }

      while (q -- )
      {
          int l, r, x;
          scanf("%d%d%d", &l, &r, &x);
          l --, r --;

          int t1 = lower_bound(v[x].begin(), v[x].end(), l) - v[x].begin();
          int t2 = upper_bound(v[x].begin(), v[x].end(), r) - v[x].begin();

          printf("%d\n", t2 - t1);
      }
}

G 分割

将x与y升序排序,然后计算相邻差值。
我们的矩形面积的计算,我们去看细节,发现,所有矩形都是由这些基础的矩形组成。
而我们要做的就是看看每个基础矩形的贡献是多少。
(i - 1) *x[i] * (n - i + 1)
然后我们将一行的贡献值(res)计算出来。然后这个方法去找列的矩形。

注意取模

#include <bits/stdc++.h>

using namespace std;

#define int long long

const int N = 100010, mod = 1000000007;

int n, m;
int a[N], b[N];
signed main()
{
      cin >> n >> m;
      for (int i = 1; i <= n; i ++ ) cin >> a[i];
      for (int i = 1; i <= m; i ++ ) cin >> b[i];

      sort(a + 1, a + 1 + n);
      sort(b + 1, b + 1 + m);

      for (int i = n; i >= 1; i -- )
      {
          a[i] -= a[i - 1];
          a[i] = (a[i] % mod + mod) % mod;
      }

      for (int i = m; i >= 1; i -- )
      {
          b[i] -= b[i - 1];
          b[i] = (b[i] % mod + mod) % mod;
      }
      int res = 0, ans = 0;
      for (int i = 2; i <= n; i ++ )
      {
          res = (res + ((i - 1) * a[i] % mod) * (n - i + 1) % mod) % mod;
      }

      for (int  i = 2; i <= m; i ++ )
      {
          ans = (ans + (((i - 1) * b[i] % mod) * (m - i + 1) % mod) * res % mod)% mod;
      }

      cout  << ans << endl;
      return 0;
}

I 母牛哥与子序列

显然,我们从集合中选出若干个乘在一起,将所有这种情况加起来
那么,在使用集合的时候,每个集合都面临着选或者不选两种情况,很自然的想到了多项式乘积这个知识点。
下面是公式,减一是去掉空集
在这里插入图片描述
将它展开与我们的题目含义等价

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 1000010, mod = 1000000007;

int n;
ll a[N];
ll ans = 1;

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i ++ )
    {
        ll x; scanf("%lld", &x);
        x %= mod;
        ans = ans * (x + 1) % mod;
        // ans = (ans % mod + ans * x % mod) % mod;
    }

    cout << (mod + ans - 1) % mod<< endl;

    return 0;
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值