noi.ac #45 计数

\(des\)
给定 \(n\) 的全排列 + 一个值域属于 \([1, n]\) 的元素构成长度为 \(n + 1\) 的序列
问长度为 \(i\) 的本质不同的子序列的个数

\(sol\)
小学计数题
记 \(p + 1, q - 1\) 的元素相同
从起点到第一个相同元素长度 \(p\)
从终点到第二个相同元素长度 \(q\)
对于长度为 \(i\) 的本质不同的子序列的个数
可以用全部的答案 - 出现重复的个数
显然全部的答案 \(n + 1 \choose i\)
对于重复的答案,只存在于重复的元素存在于挑选的元素中的时候
这样的话,挑选的元素只剩下 \(i - 1\) 个
枚举在 \([1, p]\) 中挑选 \(x\) 个,在 \([q, n + 1]\) 中挑选 \(i - 1 - x\) 个统计答案
。。。
这样枚举的就非常zz啊
重复的方案数显然就是 $ q + p \choose i - 1$

时间复杂度 \(O(nlogn)\)

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 10, Mod = 1e9 + 7;

#define gc getchar()

inline int read() {int x = 0; char c = gc;while(c < '0' || c > '9') c = gc;
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc; return x;}

#define LL long long
#define Rep(i, a, b) for(int i = a; i <= b; i ++)

LL fac[N] = {1};
bool vis[N];
LL n, a[N];
LL q, p;

LL Ksm(LL a, LL b) {
    LL ret = 1;
    while(b) {if(b & 1) ret = ret * a % Mod; a = a * a % Mod; b >>= 1;}
    return ret;
}

LL C(LL n_, LL m) {
    if(n_ < m || m == 0) return 0;
    return (fac[n_] * Ksm(((fac[m] * fac[n_ - m]) % Mod), Mod - 2)) % Mod;
}

int main() {
    n = read();
    Rep(i, 1, n + 1) fac[i] = (fac[i - 1] * i) % Mod;
    Rep(i, 1, n + 1) {
        a[i] = read();
        if(vis[a[i]]) {
            p = n + 1 - i;
            Rep(j, 1, i) if(a[j] == a[i]) {q = j - 1; break;}
            break;
        }
        vis[a[i]] = 1;
    }
    Rep(i, 1, n + 1) {
        LL a = C(n + 1, i), b = C(q + p, i - 1);
        LL Answer;
        if(i == 1) Answer = a - b - 1;
        else Answer = a - b;
        if(Answer < 0) Answer += Mod;
        cout << Answer << "\n";
    }
    return 0;
}

原文地址:https://www.cnblogs.com/shandongs1/p/9722911.html

时间: 2024-10-12 04:12:48

noi.ac #45 计数的相关文章

SDOI2015 寻宝游戏 | noi.ac#460 tree

题目链接:戳我 可以知道,我们相当于是把有宝藏在的地方围了一个圈,求这个圈最小是多大. 显然按照dfs序来遍历是最小的. 那么我们就先来一遍dfs序列,并且预处理出来每个点到根的距离(这样我们就可用\(dis[u]+dis[v]-2*dis[lca(u,v)]\)来表示u,v之间的距离) 怎么动态维护这个东西呢?平衡树?不存在的,开一个set就行了.每次维护一下添加或者删除产生的影响就行了. 相似的题目是noi.ac#460 tree-- 给你一棵n个点的树,每个点都有一个颜色ci. 有m次操作

noi.ac #241 distance

话说这noi.ac是为了给蒟蒻增强信心还是干啥,这比赛后面几题搞的有点水啊.. 虽然第一题比较毒.. 这T3...水的一批... 直接先预处理一下每个点为根的到其他点的距离不就行了吗? 算了不说了... 直接给代码... #include <bits/stdc++.h> #define ll long long using namespace std; const ll N = 10010; ll head[N], Next[N<<1], ver[N<<1], edge

线性代数(矩阵乘法):NOI 2007 生成树计数

这道题就是深搜矩阵,再快速幂. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <map> 5 using namespace std; 6 const int maxn=200; 7 const int mod=65521; 8 struct Matrix{ 9 long long mat[maxn][maxn]; 10 int r,c; 11 Matrix

noi.ac #46 最长上升子序列

\(des\) 长度为 \(n\) 的序列 \(A\),从中删去恰好 \(k\) 个元素(右边的元素往左边移动),记 \(cnt\) 为新 序列中 \(Ai = i\) 的元素个数(即权值与下标相同的元素的个数).求 \(cnt\) 的最大值. \(sol\) \(n ^ 2\) dp \(f_i\) 表示只保留 \(i\) 个的答案 转移 \(f_j = max(f_j, f_{j-1} + (x == j), j = min(i, m) -> 1\) 考虑 \(i\) 转移到 \(j\) 的

noi.ac #289. 电梯(单调队列)

题意 题目链接 Sol 傻叉的我以为给出的\(t\)是单调递增的,然后\(100\rightarrow0\) 首先可以按\(t\)排序,那么转移方程为 \(f[i] = min_{j=0}^{i-1}(max(t[i], f[j]) + 2 * max_{k=j+1}^i x[k])\) 不难发现,若\(i < j\)且\(x[i] < x[j]\),那么从\(i\)转移过来一定是不优的,一定是从\(i\)之前的某个位置转移过来.(f单增) 然后直接单调队列搞一搞就行了, #include&l

noi.ac#458 sequence

题目链接:戳我 蒟蒻的第一道子序列自动机! 给定两个01串A,B,求一个最短的01串,要求C不是A,B的子序列.要求如果同样短,输出字典序最小的. 那么我们先构建A,B两个串的子序列自动机.然后我们设\(f[i][j]\)表示现在已经匹配到A的第i位,B的第j位,现在还需要f[i][j]长度,才不是A,B的子序列. 那么\(f[i][j]\)从\(f[nxt_a[i][0/1]][nxt_b[i][0/1]]\)转移过来就行了. 比较重要的是如何构建出字典序最小的? 我们从x=0,y=0开始构建

@noi.ac - [email&#160;protected] cleaner

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 小Q计划在自己的新家中购置一台圆形的扫地机器人.小Q的家中有一个宽度为 m 的走廊,走廊很长,如果将这个走廊的俯视图画在平面直角坐标系上的话,那么走廊的两堵墙可以分别看作直线 y=0 和直线 y=m,两堵墙之间的部分代表走廊. 小Q会按照顺序依次在走廊中安置 n 个家具.第 i 个家具

@noi.ac - [email&#160;protected] shuffle

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 给定一个长度为 n 的序列 s1,s2,-,sn,它有 2^n?1 个非空子序列.请对于每个 k=0,1,2,-,n 统计 s 有多少非空子序列 a 经过重排成 b 后,ai = bi 的位置数量的最小可能值恰好为k. input 第一行包含一个正整数 n ,表示序列的长度. 第二行包

@noi.ac - [email&#160;protected] game

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 小 Q 和小 T 正在玩一种双人游戏.m 张木牌从左往右排成一排,第 i 张木牌上写着一个正整数 bi.小 Q 和小 T 轮流行动总计 m 轮,小 Q 先手.在每一轮中,行动方需要选择最左或者最右的一张木牌并将其拿走.游戏最后每个人的得分即为他拿走的木牌上写着的数字之和,得分较大的一方