2017中国大学生程序设计竞赛-哈尔滨站
去年哈尔滨现场赛的题目,只补了四道。 区域赛题目真的好难啊……
补题链接:https://vjudge.net/contest/198451
F - Permutation 构造
给出n,构造出满足
pi≡0(mod|pi−pi−2|)
p
i
≡
0
(
m
o
d
|
p
i
−
p
i
−
2
|
)
的一个长度为n的排列,注意是排列,不能有重复的数字出现,每个数字只能用一次,所以只要 % 1 == 0 就可以了
比如n = 7的构造方法是 1 5 2 6 3 7 4 以此类推……
H - A Simple Stone Game 质因数分解
给一个长度为n的序列,每个数代表每一堆的石子数,每次操作可以将一个石子移动到另一堆中,求最少的操作次数,使得对于一个数x,所有的数%x = 0
所以只要分解石子总数的质因子就好了,然后枚举每个质因子作为x,然后对于每一个x求出最少的操作次数,取一个最小值。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
typedef long long LL;
LL a[N], n;
vector<LL>p,num;
void Factor(LL nn)
{
for(LL i = 2; i*i <= nn; i++)
{
if(nn % i == 0) p.push_back(i);
while(nn % i == 0) nn /= i;
}
if(nn > 1) p.push_back(nn);
}
int main()
{
LL t;
scanf("%lld",&t);
while(t--)
{
p.clear();
scanf("%lld",&n);
LL sum = 0;
for(LL i = 1; i <= n; i++)
{
scanf("%lld",&a[i]);
sum += a[i];
}
Factor(sum);
sort(p.begin(),p.end());
LL ans = LONG_LONG_MAX;
for(LL i = 0; i <= p.size()-1; i++)
{
LL tmp = p[i];
num.clear();
LL cur = 0;
for(LL j = 1; j <= n; j++)
{
LL xx = a[j] % tmp;
//printf("%d %% %d = %d\n",a[j],tmp,xx);
//printf("%d ",xx);
if(xx)
{
cur += xx;
num.push_back(xx);
}
}
sort(num.begin(),num.end());
LL check = 0;
for(LL j = num.size()-1; j >= 0; j--)
{
check += tmp - num[j];
cur -= tmp;
if(cur == 0) break;
}
ans = min(ans,check);
}
printf("%lld\n",ans);
}
return 0;
}
A - Palindrome Manacher + 树状数组
给一个字符串S,求这个字符串满足
S[i]=S[2n−i]=S[2n+i−2](1≤i≤n)
S
[
i
]
=
S
[
2
n
−
i
]
=
S
[
2
n
+
i
−
2
]
(
1
≤
i
≤
n
)
的子串的个数。比如:abcbabc
顺道复习了一下Manacher
首先,我们可以通过Manacher算法求出对于每一个字符来说,以它为中心的回文半径的长度。通过观察,我们可以发现对于满足上面式子的字符串,有两个对称点,比如abcbabc的对称点就是下标为3和5的字符。令这两个下标分别为
i
i
和
(i<j)
(
i
<
j
)
,对于这两个点,满足下面的式子
i<j
i
<
j
①
j−i<=p[i]
j
−
i
<=
p
[
i
]
②
j−i<=p[j]
j
−
i
<=
p
[
j
]
③
可以得到
i>=j−p[j]
i
>=
j
−
p
[
j
]
④
把满足④的式子放入树状数组中,统计在
(i,i+p[i]]
(
i
,
i
+
p
[
i
]
]
范围内的
j
j
<script type="math/tex" id="MathJax-Element-912">j</script>的数目
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5e5 + 10;
LL Mp[N *2], Ma[N * 2];
LL R[N * 2];//回文半径
char s[N];
vector<LL>G[N];
LL c[N], len;
LL lowbit(LL x)
{
return x & (-x);
}
void Update(LL k,LL x)
{
for(LL i = k; i <= len; i += lowbit(i))
{
c[i] += x;
}
}
LL sum(LL k)
{
LL s = 0;
for(LL i = k; i >= 1; i -= lowbit(i))
{
s += c[i];
}
return s;
}
void Manacher(char s[],LL len)
{
LL l = 0;
Ma[l++] = '$';
Ma[l++] = '#';
for(LL i = 0; i < len; i++)
{
Ma[l++] = s[i];
Ma[l++] = '#';
}
Ma[l] = 0;
LL mx = 0, id = 0;
for(LL i = 0; i < l; i++)
{
Mp[i] = mx > i ? min(Mp[2*id-i],mx-i):1;
while(Ma[i+Mp[i]] == Ma[i-Mp[i]]) Mp[i]++;
if(i+Mp[i] > mx)
{
mx = i + Mp[i];
id = i;
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(c,0,sizeof(c));
for(int i = 0; i < N; i++) G[i].clear();
scanf("%s",s);
len = strlen(s);
Manacher(s,len);
LL k = 1;
for(LL i = 2; i < 2*len+2; i+=2)
{
R[k] = Mp[i]/2 - 1;
G[k - R[k]].push_back(k);
k++;
}
LL ans = 0;
for(LL i = 1; i <= len; i++)
{
for(LL j = 0; j < G[i].size(); j++)
{
//printf("%d ",G[i][j]);
Update(G[i][j],1);
}
ans += (LL) sum(min(R[i]+i,len)) - sum(i);
}
printf("%lld\n",ans);
}
return 0;
}