emmm,先贴一个没听一次的定理 Lindström–Gessel–Viennot lemma
然后存一下递推求组合数的模板
#include
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const int N = 2500;
ll n, m;
ll C[N][N];
//递推求组合数
void Init() {
for(int i = 0; i < N; i ++) {
for(int j = 0; j <= i; j ++) {
if(j == 0 || j == i) {
C[i][j] = 1;
}
else {
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
}
}
}
}
int main() {
Init();
while(~ scanf("%lld%lld", &n, &m)) {
ll x = (C[n + m][n] * C[n + m][n]) % mod;
ll y = (C[n + m][n + 1] * C[n + m][n - 1]) % mod;
printf("%lld\n", ((x - y) % mod + mod) % mod);
}
return 0;
}
把这个矩阵看成是无向图的邻接矩阵,然后每个点的度为2,且没有自环,所以每个点属于且仅属于一个环
#include
using namespace std;
typedef long long ll;
const ll maxn = 100100;
ll n, m;
ll d[maxn], f[maxn];
ll add(ll a, ll b) {
ll ret = a + b;
return ret > m ? ret - m : ret;
}
int main() {
while(~ scanf("%lld %lld", &n, &m)) {
d[1] = 0;
d[2] = d[3] = 1;
f[3] = 1;
for(ll i = 4; i <= n; i ++) {
ll tmp = (i - 1) * (i - 2) / 2 % m;
tmp = tmp * d[i - 3] % m;
f[i] = add(tmp, (i - 1) * f[i - 1] % m);
tmp = (i - 1) * d[i - 2] % m;
d[i] = add(tmp, f[i]);
}
printf("%lld\n", d[n] % m);
}
return 0;
}
#include
using namespace std;
int n, m1, m2, u[100], v[100], g1[10][10], g2[10][10], a[10];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
while (cin >> n >> m1 >> m2) {
memset(g1, 0, sizeof(g1));
memset(g2, 0, sizeof(g2));
for (int i = 1; i <= m1; i++) {
cin >> u[i] >> v[i];
g1[u[i]][v[i]] = g1[v[i]][u[i]] = 1;
}
for (int i = 1; i <= m2; i++) {
int x, y;
cin >> x >> y;
g2[x][y] = g2[y][x] = 1;
}
for(int i=1;i<=n;i++) a[i]=i;
int ans = 0, num = 0,kase=0;
do {
int flag1 = 1, flag2 = 1;
for (int i = 1; i <= m1; i++) {
int x = a[u[i]], y = a[v[i]];
if (!g1[x][y])flag1 = 0;
if (!g2[x][y])flag2 = 0;
}
ans += flag2;
num += flag1;
} while (next_permutation(a + 1, a + n + 1));
cout << ans / num << "\n";
}
}
#include
using namespace std;
using namespace __gnu_cxx;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int MAX=1e5+10;
const ll mod=1e9+7;
ll dp[MAX][12];
int last[12],pre[MAX],a[MAX];
int main(){
int n, m, k;
while(~ scanf("%d %d %d", &n, &m, &k)){
for(int i = 1; i <= k; i ++)
last[i] = 0;
for(int i = 1; i <= n; i ++){
scanf("%d", &a[i]);
pre[i] = last[a[i]];
last[a[i]] = i;
}
for(int i = 0; i <= m; i ++)
dp[i][i] = 1;
for(int i = 1; i <= n; i ++){
dp[i][0] = 1;
for(int j = 1; j <= min(i - 1, m); j ++){
dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1]) % mod;
if(pre[i] && i - pre[i] <= j){
dp[i][j] -= dp[pre[i] - 1][j - (i - pre[i])];
dp[i][j] %= mod;
dp[i][j] = (dp[i][j] + mod) % mod;
}
}
}
printf("%lld\n", dp[n][m]);
}
return 0;
}
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const LL mod = 1000000007;
const int N = 1005;
LL C[N][N];
LL B[N],Inv[N];
LL Tmp[N];
LL n;
void Init()
{
//预处理组合数
for(int i=0; i
补不动,补不动,后缀自动机,什么鬼。。。
#include
#include
#include
#include
#include
#define rep(i,e) for(int i=0;i<(e);i++)
#define PB push_back
#define scd(a) scanf("%d",&a)
using namespace std;
typedef long long ll;
const int N = 1e6+10;
int idx;
int maxlen[N], minlen[N], trans[N][27], slink[N];
int new_state(int _maxlen, int _minlen, int* _trans, int _slink) {
maxlen[idx] = _maxlen;
minlen[idx] = _minlen;
for(int i = 0; i < 27; i++) {
if(_trans == NULL)
trans[idx][i] = -1;
else
trans[idx][i] = _trans[i];
}
slink[idx] = _slink;
return idx++;
}
int add_char(char ch, int u) {
int c = ch - 'a';
int z = new_state(maxlen[u] + 1, -1, NULL, -1);
while(u != -1 && trans[u][c] == -1) {
trans[u][c] = z;
u = slink[u];
}
if(u == -1) {
minlen[z] = 1;
slink[z] = 0;
return z;
}
int x = trans[u][c];
if(maxlen[u] + 1 == maxlen[x]) {
minlen[z] = maxlen[x] + 1;
slink[z] = x;
return z;
}
int y = new_state(maxlen[u] + 1, -1, trans[x], slink[x]);
minlen[z] = minlen[x] = maxlen[y] + 1;
slink[z] = slink[x] = y;
while(u != -1 && trans[u][c] == x) {
trans[u][c] = y;
u = slink[u];
}
minlen[y] = maxlen[slink[y]] + 1;
return z;
}
int n;
char s[N];
char f[200]; // 存映射
vector ve;
void deal(int &st){
rep(k,3) f[ve[k] + 'a'] = k + 'a';
rep(i,n){
st = add_char(f[s[i]], st);
}
}
ll dp[N];
ll dfs(int st){
ll& ret = dp[st];
if(ret!=-1) return ret;
ret = st!=0; // 不算状态0
rep(i,26){
if(trans[st][i]!=-1){
ret += dfs(trans[st][i]);
}
}
return ret;
}
void work(){
idx=0;
scanf("%s",s);
n = strlen(s);
ve.clear();
rep(i,3)ve.PB(i);
int sta = new_state(0,0,NULL,-1);
do{
deal(sta);
sta = add_char(26 + 'a', sta);
}while(next_permutation(ve.begin(), ve.end()));//全排列
rep(i,idx) dp[i] = -1;
int cnt = -1; // 因为状态0是空串不算进去
for(int st = 0;st!=-1;st = trans[st][0], cnt++); // 计算同字符的串的数量(最大长度)
printf("%lld\n", (dfs(0)+cnt*3)/6);
}
int main() {
while(scd(n)==1)
work();
}
第一次写树状数组,还有些地方不是很通透,比如神奇的lowbit。
先说一下最基础的树状数组,它就是维护区间和的,然后借助一些辅助数组,完成一些别的功能,比如,这一题就完成了区间不同元素的个数。
这题还用到一个倍增——将数列首尾相连,把两段连成一段
#include
using namespace std;
const int N = 2e5 + 10;
int a[N];
int pre[N];
bool vis[N];
int last[N];
int nxt[N];
int bit[N];
int ans[N];
int lowbit(int x){
return x & -x;
}
void update(int x, int y){
for(int i = x; i < N; i += lowbit(i)){ //bit数组下标到不了N
bit[i] += y;
}
}
int query(int x){
int ans = 0;
for(int i = x; i > 0; i -= lowbit(i)){ //bit数组是从2^0 ,即1开始计算的
ans += bit[i];
}
return ans;
}
int query(int x, int y){
return query(y) - query(x - 1);
}
struct Seg{
int l, r, id;
}seg[N];
bool cmp(Seg a, Seg b){
return a. l < b. l;
}
int main(){
int n, q;
while(~scanf("%d%d", &n, &q)){
memset(bit, 0, sizeof(bit));
memset(vis, false, sizeof(vis));
memset(nxt, -1, sizeof(pre));
memset(last, -1, sizeof(last));
for(int i = 1; i <= n; i ++){
scanf("%d", &a[i]);
a[i + n] = a[i];
}
n *= 2;
pre[0] = 0;
for(int i = 1; i <= n; i ++){
if(! vis[a[i]]){
vis[a[i]] = true;
pre[i] = pre[i - 1] + 1;
}
else{
pre[i] = pre[i - 1];
}
if(~last[a[i]]){
nxt[last[a[i]]] = i;
}
last[a[i]] = i;
}
for(int i = 0; i < q; i ++){
scanf("%d%d", &seg[i]. l, &seg[i]. r);
seg[i]. l += n / 2;
swap(seg[i]. l, seg[i]. r);
seg[i]. id = i;
}
sort(seg, seg + q, cmp);
int nowl = 1;
for(int i = 0; i < q; i ++){
while(nowl < seg[i]. l){
if(~ nxt[nowl]){
update(nxt[nowl], 1);
}
nowl ++;
}
ans[seg[i]. id] = pre[seg[i]. r] - pre[seg[i]. l - 1] + query(seg[i]. l, seg[i]. r);
}
for(int i = 0; i < q; i ++){
printf("%d\n", ans[i]);
}
}
return 0;
}