zoukankan      html  css  js  c++  java
  • 模拟测试20191004

    T1:Reverse

    如果直接暴力建图跑bfs时空复杂度都是$O(n^{2})$的,考虑怎么优化bfs的过程

    我们发现主要瓶颈在于有许多点被扫到了多次

    考虑用一个set存剩下的点,

    由于每个点能走到的点在相同奇偶性下是连续的,我们把奇数和偶数分开来存

    每次用一个点扩展时找到他能走的区间,把这些点从set里删掉就好了

    注意区间范围

    复杂度$O(nlogn)$

    T2:Silhouette

     我至今都对于自己考试时能想出来这个容斥而惊讶

    我们显然的发现a和b的顺序对答案没有影响

    考虑把两个数组排序

    通过手模(打表)我们发现每个点能控制的是一个L形

    但是L形不好统计,由于L可以分成两个矩形,考虑一个矩形怎么统计答案

    设$S$,表示当前的$min(a,b)$,$f[i]$表示当前至少有i行不满足的方案数

    则有$ f[i]=C_{a}^{i} imes (s^{i} imes ((s+1)^{a-i}-s^{a-i}))^{b} $

    $ans=sum_{i=0}^{a}(-1)^{i} imes f[i] $

    那么一个L形也就很显然了

    有$  f[i]=C_{a}^{i} imes (s^{i} imes ((s+1)^{a+c-i}-s^{a+c-i}))^{b} imes (s^{i} imes (s+1)^{a-i})^{d} $

    T3:Seat

    大神题,我不会

    大脸太巨了

     1 //注意 因为出题人过于弱智
     2 //本题中odd为偶数,even为奇数
     3 #include<bits/stdc++.h>
     4 using namespace std;
     5 const int N=1030;
     6 int n,mod;
     7 int qpow(int x,int k,int ans=1){
     8     while(k){
     9         if(k&1) ans=ans*x%mod;
    10         x=x*x%mod;
    11         k>>=1;
    12     }
    13     return ans;
    14 }
    15 //dp为答案
    16 //f为题解中dp数组
    17 int dp[N][N],f[N][N],g[N][N],vis[N],inv[N],cnt[N],odd[N],pos[N];
    18 int main(){
    19     scanf("%d%d",&n,&mod);
    20     for(int i=1;i<=n;++i) inv[i]=qpow(i,mod-2);
    21     vis[0]=vis[n+1]=true;
    22     for(int i=1;i<=n;++i){
    23         int pl=0,pr=0,mx;
    24         for(int j=0;j<=n;++j){
    25             int r=j+1;
    26             while(!vis[r]) ++r;
    27             if(r-j>pr-pl) pl=j,pr=r;
    28             j=r-1;
    29         }
    30         ++cnt[mx=pr-pl>>1]; odd[mx]+=pr-pl&1;
    31         pos[i]=pl+mx; vis[pl+mx]=true;
    32     }
    33     int sum=n;
    34     for(int i=1;i<=n;++i){
    35         if(!cnt[i]) continue;
    36         int l=sum-cnt[i]+1,r=sum;
    37         if(i==1) for(int j=l;j<=r;++j) for(int k=l;k<=r;++k) dp[j][pos[k]]=inv[cnt[i]];//直接赋值为距离为1个数的逆元? 或许这里也被平均掉了
    38         else{
    39             for(int j=0;j<=cnt[i];++j) for(int k=0;k<=odd[i];++k) f[j][k]=0;//清空数组
    40             f[0][odd[i]]=1; //还没有坐人,那么该层剩下odd[i]个偶数区间的概率为1
    41             int p=l+odd[i]-1; //偶数区间长度的最后一个人
    42             for(int j=1;j<=cnt[i];++j){
    43                 int oddw=0,evenw=0;//odd为偶数 even为奇数
    44                 for(int k=0;k<=odd[i];++k){
    45                     if(!f[j-1][k]) continue;//dp转移 所以f值为0的时候可以剪枝 k表示剩余多少个偶数区间
    46                     int frac=(cnt[i]-(j-1))+k,w=0; //括号内表示剩余的区间个数 +k表示剩余多少个转移点
    47                     if(k){//还有偶区间剩余
    48                         w=f[j-1][k]*k*2%mod*inv[frac]%mod;//占一个偶区间位置 那么概率为k*2/转移点
    49                         oddw=(oddw+w*inv[odd[i]*2])%mod; //方便累加答案 对于这一次的转移 可能作用在不同的转移点
    50                         (f[j][k-1]+=w)%=mod;
    51                     }
    52                     if(cnt[i]-odd[i]){//可以向奇区间转移
    53                         w=f[j-1][k]*(frac-2*k)%mod*inv[frac]%mod;//向奇数区间转移的概率
    54                         evenw=(evenw+w*inv[(cnt[i]+odd[i])-odd[i]*2])%mod;//向不同奇数区间转移
    55                         (f[j][k]+=w)%=mod;
    56                     }
    57                 }
    58                 for(int u=l;u<=p;++u) (dp[l+j-1][pos[u]]+=oddw)%=mod,(dp[l+j-1][pos[u]+1]+=oddw)%=mod;//累加答案
    59                 for(int u=p+1;u<=r;++u) (dp[l+j-1][pos[u]]+=evenw)%=mod;//这里存在疑问 似乎将偶数区间默认加给了前面的pos
    60             }
    61             for(int j=l;j<=p;++j){//
    62                 int L=pos[j]-i+1,R=pos[j]+i;//当前的偶区间左右端点
    63                 for(int v=L;v<=R;++v){
    64                     if(v==pos[j]) continue;//不能是选择的点
    65                     for(int u=r+1;u<=n;++u){//后面每一个人
    66                         int s=v<pos[j]?v+i+1:v-i,w=dp[u][v]*inv[2]%mod;//后一个人在位置v的概率除2
    67                         (g[u][v]+=w)%=mod; (g[u][s]+=w)%=mod;//平均一下 虽然不知道为啥 但是感觉很对
    68                     }
    69                 }
    70                 for(int v=L;v<=R;++v) for(int u=r+1;u<=n;++u) dp[u][v]=g[u][v],g[u][v]=0;
    71             }
    72         }
    73         sum-=cnt[i];//考虑下一层 剩余人数减少
    74     }
    75     for(int i=1;i<=n;i++,puts("")) for(int j=1;j<=n;j++) printf("%d ",dp[i][j]);
    76     return 0;
    77 }
    skyh倾情压行注释std
  • 相关阅读:
    OC字符串处理
    用 map 表达互斥逻辑
    iOS之LLDB调试器
    iOS 线程安全 锁
    OC实现 单向链表
    iOS读取info.plist中的值
    SQLite 如何取出特定部分数据
    UIView常用的一些方法setNeedsDisplay和setNeedsLayout
    xCode常用快捷键
    oppo7.0系统手机(亲测有效)激活Xposed框架的流程
  • 原文地址:https://www.cnblogs.com/mikufun-hzoi-cpp/p/11622444.html
Copyright © 2011-2022 走看看