2021年广东工业大学第十五届文远知行杯程序设计竞赛
- [A M形字符串](https://ac.nowcoder.com/acm/contest/13504/A)
- [B 找山坡](https://ac.nowcoder.com/acm/contest/13504/B)
- [C 涂墙](https://ac.nowcoder.com/acm/contest/13504/C)
- [E 捡贝壳](https://ac.nowcoder.com/acm/contest/13504/E)
- [G 分割](https://ac.nowcoder.com/acm/contest/13504/G)
- [I 母牛哥与子序列](https://ac.nowcoder.com/acm/contest/13504/I)
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;
}