f[i]表示以字元i結尾的字串的個數。
那麼現在加入乙個字元產生的貢獻就是∑字
符集大小
i=0f
[i] ,然後把這個答案賦值給這個字元對應的位置。
考慮這麼做會不會產生相同的串?假設acbb,考慮插入第乙個b的影響會形成ab,cb,acb.那麼插入第二個b會形成abb,cbb,acbb發現這些都是新產生的不會與之前的相同,而且不會影響到a,c結尾的字串。
那麼每次轉移實際上是乘上了乙個對角線為1,某一列為1為1的矩陣。
我們可以維護矩陣的字首積,和逆矩陣的字首積。
那麼對於每次詢問都可以看成是兩個矩陣相乘。
因為矩陣是沒有交換率的,所以正矩陣維護成a1
,a2,
a3..
. 的形式
對於逆矩陣,我們要保證in
v3,i
nv2,
inv1
順次與a中對應的矩陣相乘。所以每次更新的時候是in
v[i]
=mul
(rs[
x],i
nv[i
−1])
,rs[
i]表示字元x的逆矩陣。 in
v3∗i
nv2∗
inv1
∗a1∗
a2∗a
3 這樣順次相消。
如何求乙個矩陣的逆矩陣?
什麼是逆矩陣?a∗
a−1=
e 其中e表示單位矩陣,那麼a−
1 是
a 的逆矩陣。
首先將逆矩陣賦值為單位矩陣,然後對a進行高斯消元,將a矩陣變成單位矩陣,變換過程中對a矩陣的所有操作都在逆矩陣中同等實現。做完後的逆矩陣即為所求。
如果最後無法消成單位矩陣,那麼說明該矩陣不存在逆矩陣。
#include
#include
#include
#include
#include
#define n 10
#define p 1000000007
#define ll long long
using namespace std;
struct database[n+3],inv[n+3],ans,sum[100003],sinv[100003];
int n,m; char s[100003];
data mul(data a,data b)
return c;
}ll quickpow(ll num,int
x) return ans;
}void guass(data a,data &inv)
ll t=quickpow(a.a[i][i],p-2);
for (int j=1;j<=n;j++)
for (int j=1;j<=n;j++)
if (i!=j&&a.a[j][i]) }}
}int main()
ans.a[1][1]=1;
for (int i=1;i<=n;i++) sinv[0].a[i][i]=1;
sum[1]=base[s[1]-'a'+1];
sinv[1]=inv[s[1]-'a'+1];
for (int i=2;i<=n;i++)
sum[i]=mul(sum[i-1],base[s[i]-'a'+1]),
sinv[i]=mul(inv[s[i]-'a'+1],sinv[i-1]);
scanf("%d",&m);
for (int i=1;i<=m;i++)
}
省隊集訓day6 C
給定平面上的 n 個點,其中有一些是紅的,其他是藍的.現在讓你找兩條平行的直線,使得在保證 不存在乙個藍色的點 被夾在兩條平行線之間,不經過任何乙個點,不管是藍色點還是紅色點 的前提下,被夾在平行線之間的紅色點個數最多 第1行 乙個整數 n 1 n 1000 第2.n 1行 每行是乙個點的座標以及它...
省隊集訓Round3 DAY6
這道題應該是可以通過組合數直接計算的,但是我不會數學證明,所以就用了一種簡單粗暴的方式。an s 2 ic n,i c n n i an s 2 ic n,i 2 101 8 肯定不能直接列舉,如果要計算的話也需要用到lucas定理。觀察發現這題的模數比較小,所以從模數入手。考慮lucas定理。n ...
省隊集訓DAY2
假設我們列舉數列中長度為len的區間,那麼如何判斷兩個數列可以匹配呢?對於提取的數列從小到大排序,從大到小排序,然後兩兩配對,如果所有的都滿足 h 那麼就可以匹配。應該算是貪心吧。這樣做的時間複雜度是o n le n loglen 還是上面的思想,我們如何快速判斷呢?假設我們確定了提取出的區間數列,...