2020 Multi-University Training Contest 1
1004 Distinct Sub-palindromes(签到)
题意:给定长度为
n
n
n的字符串
S
S
S,任务是输出拥有最少不同子回文串个数的
S
S
S的个数
思路:
一开始以为是dp推序列,组合数学开始了…
但是手推一下发现好像就是一个简单签到题
先找拥有最少的子回文串的序列
- n = 1 n=1 n=1:26个字母
- n = 2 n=2 n=2: 2 6 2 26^2 262( a a aa aa有俩: a , a a a,aa a,aa; a b ab ab有俩: a , b a,b a,b)
- n = 3 n=3 n=3: 2 6 3 26^3 263(自己手推一下,发现咋放都可以,不同子回文串的个数都是3)
-
n
≥
4
:
A
3
26
=
26
∗
25
∗
24
n\ge4:A_{3}^{26}=26*25*24
n≥4:A326=26∗25∗24,选择任意三个不同的字母,按着规定顺序排列(ex:abcabc),不同子回文串的个数都是3.
代码:
int main() {
LL t, n;
LL ans = 0;
cin >> t;
while (t--)
{
cin >> n;
if (n <= 3) {
cout << qpow(26, n) << endl;
}
else
{
ans = (26 * 25 * 24) % MOD;
cout << ans << endl;
}
}
return 0;
}
1009 Leading Robots
Leading Robots
题意:已知机器人
v
(
t
)
=
a
∗
t
v(t)=a*t
v(t)=a∗t,现有
n
n
n个机器人,给定机器人的当前位置
p
o
s
i
t
i
o
n
position
position,加速度
a
a
a。问经过无限长的时间后,有多少个机器人当过第一位?
思路:没啥思路,最后肯定是a最大的机器人排在第一位,把他们画成二维坐标上的线可能会清楚一点。感觉要sort搞一搞,但是到最后都没做出^^。
题目大意:给你每个机器人的初始位置和加速度,问你总共有多少个机器人有可能成为一次领导机器人(在最前面)。我们先给每个机器人的位置排序,按照位置最大的,加速度最大的优先,然后我们用栈来保存每个可能成为领导的机器人的位置,加速度和其成为领导的时间,那么很明显,在后面的机器人,如果加速度小于等于当前的机器人,那么他们是不可能成为领导人的,所以我们循环的时候可以直接continue。如果加速度大的话,那么它一定能够追上前面的机器人。
所以接下来我们要算一下它追上前面机器人的时间,希望大家的物理都学的不错,有公式 s = v 0 t + 1 2 a t 2 s=v_0t+\frac{1}{2}at^2 s=v0t+21at2。那么它追上前面那个机器人的世界就是当他们的路程一样的时候,也就是
p o s t a i l − p o s i + 0 t + 1 2 a t a i l t 2 = 0 t + 1 2 a i t 2 pos_{tail}-pos_i+0t+\frac{1}{2}a_{tail}t^2=0t+\frac{1}{2}a_it^2 postail−posi+0t+21atailt2=0t+21ait2
那么为了使得我们的结果是准确的,我们将式子化为 1 2 t 2 = p o s t a i l − p o s i a i − a t a i l \frac{1}{2}t^2=\frac{pos_{tail}-pos_i}{a_i-a_{tail}} 21t2=ai−atailpostail−posi,那么我们不用将 t t t算出来,只需要用他来比较大小,所以 1 2 t 2 \frac{1}{2}t^2 21t2完全可以代替它的,接下来我们再用分数来保存每个时间。
然后如果当前的机器人追上栈顶机器人的时间小于等于栈顶机器人成为领导人的时间,那么我们将做出栈操作,也就是说栈顶的机器人在超越别人之前已经被人超越了。
最后需要判断一下栈内是否有位置一样,加速度一样的元素,这个我们可以做个map来计数。
代码:
struct fenshu
{
int fz, fm;
bool operator <(const fenshu &a)const {
return (LL)fz*a.fm < (LL)fm*a.fz;
}
bool operator <=(const fenshu &a)const {
return (LL)fz*a.fm <= (LL)fm*a.fz;
}
bool operator ==(const fenshu &a)const {
return (LL)fz*a.fm == (LL)fm*a.fz;
}
}times[maxn];
map<pii, int > mp;
struct node {
int p, a;
}cun[maxn];
bool cmp(node a,node b){
if (a.p == b.p)return a.a > b.a;
return a.p > b.p;
}
stack<int> houxuan;
stack<fenshu>q;
int main()
{
int t, n, nw, ans, leader;
int st, temp;
pii p;
sci(t);
while (t--)
{
while (!q.empty())q.pop();
while (!houxuan.empty())houxuan.pop();
mp.clear();
ans = 0;
sci(n);
for (int i = 1; i <= n; i++) {
sci(cun[i].p);
sci(cun[i].a);
p.first = cun[i].p;
p.second = cun[i].a;
mp[p]++;
}
sort(cun + 1, cun + 1 + n, cmp);
leader = 1;
//int st;
houxuan.push(1);
q.push(fenshu{ 0,1 });
for (int i = 2; i <= n; i++) {
if (cun[i].a <= cun[houxuan.top()].a)continue;
while ((!houxuan.empty()) && (fenshu { cun[houxuan.top()].p - cun[i].p, cun[i].a - cun[houxuan.top()].a } <= q.top())) {
houxuan.pop();
q.pop();
}
q.push(fenshu{ cun[houxuan.top()].p - cun[i].p, cun[i].a - cun[houxuan.top()].a });
houxuan.push(i);
}
while (!houxuan.empty())
{
p.first = cun[houxuan.top()].p;
p.second = cun[houxuan.top()].a;
if (mp[p] == 1)ans++;
houxuan.pop();
}
printf("%d\n", ans);
}
return 0;
}
1005 Fibonacci Sum
题意:
给定N、C(
1
0
18
10^{18}
1018)、K
(
1
0
5
)
(10^5)
(105)对于Fibonacci数列进行
F
0
K
+
F
C
K
+
F
2
C
K
+
.
.
.
+
F
N
C
K
F_0^{K}+F_C^{K}+F_{2C}^{K}+...+F_{NC}^{K}
F0K+FCK+F2CK+...+FNCK进行mod
(
1
0
9
+
9
)
(10^9+9)
(109+9)的计算
思路:
已知Fibonacci数列有个通项公式:
F
n
=
1
5
[
(
1
+
5
2
)
n
−
(
1
−
5
2
)
n
]
F_n=\frac{1}{\sqrt5}[(\frac{1+\sqrt5}{2})^n-(\frac{1-\sqrt5}{2})^n]
Fn=51[(21+5)n−(21−5)n]
设
s
q
5
=
1
5
,
a
=
1
+
5
2
,
b
=
1
−
5
2
sq5=\frac{1}{\sqrt5},a=\frac{1+\sqrt5}{2},b=\frac{1-\sqrt5}{2}
sq5=51,a=21+5,b=21−5(程序计算得到
s
q
5
=
383008016
sq5=383008016
sq5=383008016)
- 代入通项公式 ⇒ s q 5 K ∗ ∑ i = 0 N ( a i C − b i c ) K \Rightarrow sq5^K*\sum_{i=0}^N (a^{iC}-b^{ic})^K ⇒sq5K∗∑i=0N(aiC−bic)K
- 二项式展开 ⇒ \Rightarrow ⇒ s q 5 K ∗ ∑ i = 0 N ∑ j = 0 K C k j a i j C ( − b ) ( k − j ) ∗ i C sq5^K*\sum_{i=0}^N \sum_{j=0}^K C_{k}^{j}a^{ijC}(-b)^{(k-j)*iC} sq5K∗∑i=0N∑j=0KCkjaijC(−b)(k−j)∗iC
设 A = a C , B = b C A=a^C,B=b^C A=aC,B=bC
- 代入 ⇒ s q 5 K ∗ ∑ i = 0 N ∑ j = 0 K C k j A i j ( − B i ) k − j \Rightarrow sq5^K*\sum_{i=0}^N \sum_{j=0}^K C_{k}^{j}A^{ij}(-B^i)^{k-j} ⇒sq5K∗∑i=0N∑j=0KCkjAij(−Bi)k−j
- 交换 ⇒ s q 5 K ∗ ∑ j = 0 K C k j ( − 1 ) k − j ∑ i = 0 N ( A j ) i ( B k − j ) i \Rightarrow sq5^K* \sum_{j=0}^KC_{k}^{j}(-1)^{k-j}\sum_{i=0}^N (A^j)^i(B^{k-j})^i ⇒sq5K∗∑j=0KCkj(−1)k−j∑i=0N(Aj)i(Bk−j)i
- ∑ i = 0 N ( A j ) i ( B k − j ) i ⇒ ∑ i = 0 N ( A j ∗ B k − j ) i \sum_{i=0}^N (A^j)^i(B^{k-j})^i\Rightarrow\sum_{i=0}^N (A^j*B^{k-j})^i ∑i=0N(Aj)i(Bk−j)i⇒∑i=0N(Aj∗Bk−j)i
有等比求和公式, ∑ i = 0 N x i = x N + 1 − 1 x − 1 \sum_{i=0}^N x^i=\frac{x^{N+1}-1}{x-1} ∑i=0Nxi=x−1xN+1−1
- ∑ i = 0 N ( A j ∗ B k − j ) i ⇒ ( A j B k − j ) N + 1 − 1 A j B k − j − 1 \sum_{i=0}^N (A^j*B^{k-j})^i\Rightarrow \frac{(A^jB^{k-j})^{N+1}-1}{A^jB^{k-j}-1} ∑i=0N(Aj∗Bk−j)i⇒AjBk−j−1(AjBk−j)N+1−1
所以问题就转化成了:
s
q
5
K
∗
∑
j
=
0
K
C
k
j
(
−
1
)
k
−
j
(
A
j
B
k
−
j
)
N
+
1
−
1
A
j
B
k
−
j
−
1
sq5^K*\sum_{j=0}^KC_{k}^{j}(-1)^{k-j} \frac{(A^jB^{k-j})^{N+1}-1}{A^jB^{k-j}-1}
sq5K∗∑j=0KCkj(−1)k−jAjBk−j−1(AjBk−j)N+1−1
(
A
=
a
C
,
B
=
b
C
)
(A=a^C,B=b^C)
(A=aC,B=bC)
这个代码就比较好写啦^^
注意点:
直接在for循环里面qpow会t,代码如下:
LL fac[maxn], invfac[maxn];
LL sqt5 = 383008016;//根号5二次剩余
LL inv2, invsq5;
LL a, b;
void initfac(LL n) {
fac[0] = 1;
for (LL i = 1; i <= n; i++) { fac[i] = fac[i - 1] * i%MOD; }
invfac[n] = quick_mod(fac[n], MOD - 2, MOD);
for (LL i = n - 1; i >= 0; i--) { invfac[i] = invfac[i + 1] * (i + 1) % MOD; }
return;
}
LL cm(LL n, LL m) {
if (m<0 || m>n) return 0;
return fac[n] * invfac[n - m] % MOD*invfac[m] % MOD;
//return (fac[n] * qpow(fac[m], MOD - 2) % MOD*qpow(fac[n - m], MOD - 2) % MOD) % MOD;
}
LL solve(LL n, LL c, LL k) {
LL ans = 0;
LL A, B;
LL tt, fenmu, CK;
A = quick_mod(a, c % (MOD - 1), MOD);
B = quick_mod(b, c % (MOD - 1), MOD);
/*cout << "ans1: " << -1 * cm(1, 0)*(quick_mod(B, (n + 1) % (MOD - 1), MOD) - 1)*(quick_mod(B - 1, MOD - 2, MOD)) % MOD << endl;
cout << "ans2:" << cm(1, 1)*(quick_mod(A, (n + 1) % (MOD - 1), MOD) - 1)*(quick_mod(A - 1, MOD - 2, MOD)) % MOD << endl;*/
for (LL j = 0; j <= k; j++) {
tt = (quick_mod(A, j, MOD)*quick_mod(B, k - j, MOD)) % MOD;
if (tt == 1) {
tt = cm(k, j)*(n + 1) % MOD;
if ((k - j) % 2)tt *= -1;
ans = (tt + ans + MOD) % MOD;
continue;
}
fenmu = (tt - 1 + MOD) % MOD;
tt = quick_mod(tt, (n + 1) % (MOD - 1), MOD);
tt = (tt - 1 + MOD) % MOD;
CK = tt * quick_mod(fenmu, MOD - 2, MOD) % MOD;
CK = (cm(k, j)*CK) % MOD;
//cout << cm(k, j) << endl;
if ((k - j) % 2)CK *= -1;
//cout << "teat: " << CK << endl;
//cout << "test2: " << CK << endl;
ans = (CK + ans + MOD) % MOD;
}
ans = (quick_mod(invsq5, k, MOD)*ans) % MOD;//sq5^K
return ans;
}
int main() {
int t;
LL n, c, k;
inv2 = quick_mod(2, MOD - 2, MOD);//2的逆元
invsq5 = quick_mod(sqt5, MOD - 2, MOD);//根号5分之一的逆元
a = (1 + sqt5)*inv2%MOD;
b = (1 - sqt5 + MOD) % MOD*inv2%MOD;
//cout << a << " " << b << endl;
sci(t);
/*for (LL i = 1; i <= MOD; i++) {
if (i*i%MOD == 5) { cout << i << endl; break; }
}*/
initfac(1e5+5);//初始化,之后要计算排列组合
while (t--)
{
scanf("%lld%lld%lld", &n, &c, &k);
printf("%lld\n", solve(n, c, k));
}
return 0;
}
优化:
在j的循环内对于
(
A
j
B
k
−
j
)
N
+
1
(A^jB^{k-j})^{N+1}
(AjBk−j)N+1的循环进行优化,不要每次都qpow,因为他们有一个初始值
A
0
B
k
A^0B^k
A0Bk,然后只需要每次进行增量
A
B
−
1
AB^{-1}
AB−1,就可以得到这次的
A
j
B
k
−
j
A^jB^{k-j}
AjBk−j
cndmmdldasfhilskkju气死我了wa死了找不出错哪了不管了谁爱做谁做cnmmmmm
🐂我找到了^^tt=1的时候没有mod,好,不愧是我
LL fac[maxn], finv[maxn];
LL sqt5 = 383008016ll;//根号5二次剩余
LL inv2, invsq5;
LL a, b;
void initfac(LL n) {
fac[0] = 1; for (LL i = 1; i <= n; i++) { fac[i] = fac[i - 1] * i%MOD; }
finv[n] = quick_mod(fac[n], MOD - 2);
for (LL i = n - 1; i >= 0; i--) { finv[i] = finv[i + 1] * (i + 1ll) % MOD; }
return;
}
LL cm(LL n, LL m) {//计算组合数
if (m<0 || m>n) return 0;
return (fac[n] * finv[n - m]) % MOD*finv[m] % MOD;
//return (fac[n] * qpow(fac[m], MOD - 2) % MOD*qpow(fac[n - m], MOD - 2) % MOD) % MOD;
}
LL solve(LL n, LL c, LL k) {
LL ans = 0ll;
LL A, B;
LL tt, chushi;
A = quick_mod(a, c % (MOD - 1ll));
B = quick_mod(b, c % (MOD - 1ll));
LL del = A * quick_mod(B, MOD - 2ll) % MOD;
chushi = quick_mod(B, k );//初始值:B^k
/*cout << "ans1: " << -1 * cm(1, 0)*(quick_mod(B, (n + 1) % (MOD - 1), MOD) - 1)*(quick_mod(B - 1, MOD - 2, MOD)) % MOD << endl;
cout << "ans2:" << cm(1, 1)*(quick_mod(A, (n + 1) % (MOD - 1), MOD) - 1)*(quick_mod(A - 1, MOD - 2, MOD)) % MOD << endl;*/
for (LL j = 0; j <= k; j++) {
if (chushi == 1) {
tt = (n + 1ll) % MOD;
}
else {
tt = (((quick_mod(chushi, (n + 1ll) % (MOD - 1)) - 1 + MOD) % MOD)*(quick_mod((chushi - 1 + MOD) % MOD, MOD - 2))) % MOD;
}
tt = cm(k, j)*tt%MOD;
if ((k - j) % 2 ) {
ans = (ans - tt + MOD) % MOD;
}
else {
ans = (ans + tt) % MOD;
}
chushi = (chushi * del) % MOD;
}
ans = (quick_mod(invsq5, k)*ans) % MOD;//sq5^K
return ans;
}
int main() {
int T;
LL n, c, k;
inv2 = quick_mod(2ll, MOD - 2ll);//2的逆元
invsq5 = quick_mod(sqt5, MOD - 2ll);//根号5分之一的逆元
//cout << invsq5 << endl;
a = (1ll + sqt5)*inv2%MOD;
b = (1ll - sqt5 + MOD) % MOD*inv2%MOD;
//cout << a << " " << b << endl;
sci(T);
initfac(1ll*1e5);//初始化,之后要计算排列组合
while (T--)
{
scanf("%lld%lld%lld", &n, &c, &k);
printf("%lld\n", solve(n, c, k));
}
return 0;
}