noi.ac #528 神树和排列

题目链接:戳我

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
#define MAXN 8010
#define mod 1000000007
#define ll long long
int n,m,a[MAXN],flag[MAXN],cnt[MAXN],f[2][MAXN],sum[MAXN];
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if(a[x]){puts("0");return 0;}
        if(flag[y]){puts("0");return 0;}
        if(y==n&&x!=n){puts("0");return 0;}
        if(x==n&&y!=n){puts("0");return 0;}
        a[x]=y;flag[y]=1;//a[x]=y表示位置x预定的是y
    }
    //f[i][j]表示统计到前i位,其中最大的是j的方案数
        //根据题目中的排序规则,最大的一定在最右边
    for(int i=1;i<=n;++i) cnt[i]=cnt[i-1]+flag[i];
    f[0][0]=1;
    for(int i=0;i<=n;++i) sum[i]=1;
    for(int i=1;i<=n;++i)
    {
        int now=i&1,pre=now^1;
        memset(f[now],0,sizeof(f[now]));
        //j一定在第i位
        for(int j=i;j<=n;++j)
        {
            if(!a[i-1])//i-1的位置没有被预定
            {
                f[now][j]=((f[now][j]+1ll*f[pre][j]*(j-(i-1)-cnt[j-1])%mod)%mod+sum[j-1])%mod;
                //乘上的系数是该位可以放哪些值
            }
            else if(j>a[i-1])//如果i-1的位置被预定了,且j大于i-1位置预定的值
                f[now][j]=(f[pre][j]+f[pre][a[i-1]])%mod;
        }
        sum[i-1]=0;
        for(int j=i;j<=n;++j) sum[j]=(sum[j-1]+(flag[j]?0:f[now][j]))%mod;
        //sum[j]表示以1...j为最大的值的前缀和
        //如果这个位置被预定了,那么就是0,如果没有,就加上这一位的值
        if(a[i])//如果这个位置被预定了
        {
            flag[a[i]]=0;//a[i]这个数没有预定了,以消除后面统计前缀和的影响
            for(int j=a[i];j<=n;++j) --cnt[j];//cnt[j]表示前j大的数已经被放了几个了,同上
        }
    }
    printf("%d\n",f[n&1][n]);
    return 0;
}

原文地址:https://www.cnblogs.com/fengxunling/p/11135492.html

时间: 2024-10-08 10:32:24

noi.ac #528 神树和排列的相关文章

noi.ac #525 神树的权值

mcfx神仙的题qwq 题目链接:戳我 首先,我们知道30%的分还是挺好做的 直接枚举根,然后dfs一遍以\(O(n)\)的时间复杂度求出来有多少神仙点 代码如下: #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> #define MAXN 100010 using namespace std; int n,t; in

noi.ac #529 神树的矩阵

题目链接:戳我 当 \(max(n, m) \ge 3\) 时,可以如下构造: 考虑下面这样三个矩阵,红 + 蓝 ? 绿得到的矩阵是一个第一行和最后一行全是 1,其他地方全是 0 的矩阵. 那么如果需要把中间某个位置变成 1,可以在红或蓝矩阵中的对应位置加一个 1. 如果需要把第一行或最后一行某个位置变成 0,可以在绿矩阵中的对应位置加一个 1. (图床挂了......等回来我再放图片QAQ) 然后对于其他情况分别特判就行了(具体哪些可以看main函数) #include<iostream>

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.ac #45 计数

\(des\) 给定 \(n\) 的全排列 + 一个值域属于 \([1, n]\) 的元素构成长度为 \(n + 1\) 的序列 问长度为 \(i\) 的本质不同的子序列的个数 \(sol\) 小学计数题 记 \(p + 1, q - 1\) 的元素相同 从起点到第一个相同元素长度 \(p\) 从终点到第二个相同元素长度 \(q\) 对于长度为 \(i\) 的本质不同的子序列的个数 可以用全部的答案 - 出现重复的个数 显然全部的答案 \(n + 1 \choose i\) 对于重复的答案,只存

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 个家具