前言
- 鸣谢学长Kersen
- 这两天推式子推的我挺快乐的的就,记录一下自己推数学式子的过程
- updata on :2020.12.3
修改了自己写炸的latex顺便再加一个题CF1422C难受,没有嫖到学长的学习资料还是有点小失落,但貌似我可以跟别人嫖一下
前缀和聚集地
定义一个函数
(s(l,r) = sumlimits_{i = l}^{r}a_i imes sumlimits_{i = l}^{r}b_i)
要求
(sumlimits_{l = 1}^{n}sumlimits_{r = l}^{n}s(l,r))
1. 可以凑到一起,得到这样一个式子
2. 进一步讲里面的化简
令(suma[])为(a)的前缀和, (sumb[])为(b)的前缀和
将最后一个(sumlimits_{i = l}^{r} b_i)变形为(sumb[r]-sumb[l-1])
3.得到一个(消去一重循环)
(sumb[])数组可以通过输入的时候预处理来解决,考虑再消去一重循环,发现(sumlimits_{i = l}^{r}a_i)这里也可以预处理出来,就
4.进而得到了下面的式子
发现现在的时间复杂度已经由(n^4) 降到了(n^2),但是仍然不够优秀,再次考虑再去消去一重循环将括号内的式子进行处理
令
- (qz[i])为(suma[i] imes sumb[i])的前缀和
- (qza[i]) 为(suma[i])的前缀和
- (qzb[i]) 为(sumb[i])的前缀和
5.可以将给式子这样套一个括号
(sumlimits_{ l = 1}^{n}(sumlimits_{r = l}^{n}(suma[r] imes sumb[r] + suma[l-1] imes sumb[l-1] - suma[r] imes sumb[l - 1] - sumb[r] imes suma[l - 1]))
6.式子就变成了
(sum limits_ { l = 1}^{n}[\(qz[n] -qz[l-1]) + \(n - l +1) imes (suma[l - 1] imes sumb[l-1]) \- sumb[l-1] imes (qza[n]-qza[l-1])\ - suma[l-1] imes (qzb[n]-qzb[l-1])])
code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#define int long long
using namespace std;
const int N = 5e5+100;
const int mod = 1e9+7;
int read(){
int s = 0 ,f = 1; char ch = getchar();
while(ch < '0'||ch > '9'){if(ch == '-') f = -1 ; ch = getchar();}
while(ch >= '0'&&ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
return s * f;
}
int a[N] ,b[N];
int suma[N] ,sumb[N];
int qz[N], qza[N],qzb[N];
signed main(){
int n = read();
for(int i = 1 ; i <= n ;i++) {
a[i] = read();
suma[i] = (suma[i - 1] + a[i]) % mod;
}
for(int i = 1 ; i <= n ;i++ ) {
b[i] = read();
sumb[i] = (sumb[i - 1] + b[i]) % mod;
}
for(int i = 1 ; i <= n ;i++) {
qza[i] = (qza[i - 1] + suma[i]) % mod;
qzb[i] = (qzb[i-1] + sumb[i]) % mod;
qz[i] = (qz[i - 1] + (suma[i] * sumb[i]) % mod) % mod;
}
int ans = 0;
for(int i = 1 ; i <= n ;i++) {
int ans1 = ( (qz[n] - qz[i - 1] + mod) % mod) ;
int ans2 = ((n - i + 1) * ((suma[i - 1] * sumb[i - 1]) % mod) + mod) % mod ;
int ans3 = ( suma[i - 1] * ( (qzb[n] - qzb[i - 1] + mod) % mod ) + mod ) % mod;
int ans4 = ( sumb[i - 1] * ( (qza[n] - qza[i - 1] + mod) % mod ) + mod ) % mod;
ans = (ans + ans1 + ans2 - ans3 - ans4 + mod) % mod;
}
cout << (ans + mod) % mod;
return 0;
}
不鸽了
因为是学姐的个人题,就不粘链接了
简述题意输入一个(n) ,下面一行输入(n)个整数,求
1. 对于括号里的式子可以很简单的用完全平方公式化简
得到
2.仍然还是那个方法套个括号
令
- (sum_i)为(a_i)的前缀和
- (pow_i)为(a_i^2)的前缀和
- (sumpow_i)为(pow_i)的前缀和
化简得到
就可以得到一个(O(n))的算法,但是我也不知道为啥考场写了个这么奇怪的代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#define int long long
using namespace std;
const int N = 1e6+100;
const int mod = 998244353 ;
inline int read(){
int s = 0 ,f = 1; char ch = getchar();
while(ch < '0'||ch > '9'){if(ch == '-') f = -1 ; ch = getchar();}
while(ch >= '0'&&ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
return s * f;
}
int w[N],pow[N],sum[N],sum_pow[N];
int ans = 0;
signed main(){
int n = read() ;
for(int i = 1 ; i <= n ;i++) {
w[i] = read();
sum[i] = (sum[i] + (sum[i-1] + w[i]) % mod) % mod;
pow[i] = (w[i] % mod * w[i] % mod) % mod;
sum_pow[i] = (sum_pow[i-1] + pow[i]) % mod;
}
ans = ans + (sum_pow[n] * (n - 1) + mod) % mod ;
for(int i = 1 ; i < n ;i++){
ans += mod;
ans = (ans - 2 * w[i] * (sum[n] -sum[i] + mod)) % mod;
}
printf("%lld",(ans+ mod) % mod );
return 0;
}
学长更改题面,我读错题导致我造了一个题推出另一个题挺有意思的式子,先写在前面
我读为:
读入一个数字串,可以从前面或者后面截取任意长度的一个串求出所有情况,对长度大于1的串,除最后一个数外都乘10,求总和对 1e9+7取模
打个表:
1 2 3 4 5
就会得到这样一个表
((1) + (10 + 2) +( 10 + 20 + 3 )+ (10 + 20 + 30 + 4)+ (10 + 20 + 30 + 40 + 5))
((2) + (20 + 3) +(20 + 30 + 4 )+ (20 + 30 + 40 + 5))
((3) + (30 + 40) +(30 + 40 + 5))
((4) + (40 + 5))
((5))
就会很快乐的得到这样一个式子
令
- 数字串长为(len)
- 每一位上的数( imes)之后为(ten[i])
然后样例二过不去,我就知道坏事了,我读错题了,心态当场崩溃,后面的暴力也不想写了,好吧,自己还是考场心态调整的不行
放出自己读错题的代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#define int long long
using namespace std;
const int N = 2e6+100;
const int mod = 1e9+7;
int read(){
int s = 0 ,f = 1; char ch = getchar();
while(ch < '0'||ch > '9'){if(ch == '-') f = -1 ; ch = getchar();}
while(ch >= '0'&&ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
return s * f;
}
char s[N];
int num[N];
int ten[N];
int sum[N];
int sum_10[N];
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
cin>>s;
int len = strlen(s);
for(int i = 0 ; i < len ; i++ ) {
num[i + 1] = s[i]-'0';
ten[i + 1] = num[i + 1] * 10 ;
}
int ans = 0 ;
for(int i = 1 ; i <= len ;i++) {
int ans1 = (num[i] * i) % mod;
int ans2 = (ten[i] * (len - i) * i) % mod;
ans = ( ans + (ans1 + ans2) % mod ) % mod;
}
cout << ans % mod;
}
然而真实的题面意思是这样的
- (len)仍然为这个数字串的长度
- 输入一个数字串,你可以从任意的地方抽取一块连续的部分,剩下的部分可以拼接到一起,然后每个数( imes 10^{len-i}) 求出所有情况的的和, 对1e9+7取模
Solution :
答案可以得到这样一个式子
令- (f(l,r))表示字串([L,R])组成的十进制数
考虑枚举删除的子串的最后一位(x)得到的十进制数的和为:
好吧我抄的学长博客
//知识点:瞎搞
/*
By:Luckyblock
*/
#include <cctype>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
const int kN = 2e6 + 10;
const LL mod = 1e9 + 7;
//=============================================================
int n;
char s[kN];
LL ans, sum, pow10[kN], suf[kN];
//=============================================================
inline int read() {
int f = 1, w = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
//=============================================================
int main() {
scanf("%s", s + 1);
n = strlen(s + 1);
pow10[0] = 1;
for (int i = 1; i <= n; ++ i) {
pow10[i] = pow10[i - 1] * 10ll % mod;;
}
for (int i = n; i >= 1; -- i) {
suf[i] = suf[i + 1];
suf[i] += (s[i] - '0') * pow10[n - i] % mod;
suf[i] %= mod;
}
LL val = 0;
for (int i = 1; i <= n; ++ i) {
ans += sum * pow10[n - i] % mod + (i - 1) * suf[i] % mod;
ans %= mod;
val = (10ll * val % mod + s[i] - '0') % mod;
sum = (sum + val) % mod;
}
printf("%lld
", ans);
return 0;
}
我的做法比较……难搞……我自己也不会写这个数学公式……就是前缀 + 后缀维护答案感觉自己是sb
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#define int long long
using namespace std;
const int N = 2e6+100;
const int mod = 1e9+7;
char a[N];
int num[N];
int pow[N];
int sum_pow[N];
int qian[N];
int hou[N];
int sum_qian[N];
signed main(){
cin>>a;
int len = strlen(a);
pow[0] = 1;
for(int i = 1 ; i <= len ;i++) {
pow[i] = (pow[i - 1] * 10) % mod;
num[i] = a[i-1] - '0';
}
for(int i = 1 ; i <= len ;i++) {
qian[i] = ((qian[i-1] * 10) % mod + num[i]) % mod;
sum_qian[i] =( sum_qian[i - 1 ] + qian[i] ) % mod;
}
for(int i = len ; i >= 1;i-- ) {
hou[i] = hou[i+1] + ( num[i] * pow[len - i] ) % mod;
}
int ans = 0;
for(int i = len ; i >= 1 ;i--) {
int number = (((sum_qian[i - 1] * pow[ len - i ]) % mod
+ (hou[i + 1] * i) % mod) % mod) % mod;
ans = (ans + number) % mod;
}
cout << ans % mod;
return 0;
}