zoukankan      html  css  js  c++  java
  • 转载zroi 9.16普转提(代码是自己的)

    Link:

    A:

    套路题结果想了好久……

    排序二叉树的性质就是中序遍历单调递增

    于是只考虑当前树的中序遍历的序列即可,与树的形态无关

     1 #include<bits/stdc++.h>
     2 #define maxn 100005
     3 using namespace std;
     4 typedef long long ll;
     5 int n,fa[maxn],ch[maxn][2],x;
     6 ll st[maxn],a[maxn];
     7 int top=0;
     8 void dfs(int i){
     9     if(ch[i][0]) dfs(ch[i][0]);
    10     st[++top]=a[i];
    11     if(ch[i][1]) dfs(ch[i][1]);
    12 } 
    13 ll q[maxn];
    14 int rear=0;
    15 void run(ll x){
    16     /*if(x>=q[rear]){
    17         q[++rear]=x;
    18         return;
    19     }
    20     int l=1,r=rear,mid;
    21     while(l<=r){
    22         mid=(l+r)>>1;
    23         if(q[mid-1]<=x&&x<q[mid]){q[mid]=x;return;}
    24         if(x<q[mid-1]) r=mid-1;
    25         else l=mid+1; 
    26     }*/
    27     int t=upper_bound(q+1,q+rear+1,x)-q;
    28     if(t==rear+1) q[++rear]=x;
    29     else q[t]=x;//将刚好大于它的代替 
    30 }
    31 void init(){
    32     scanf("%d",&n);
    33     for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    34     for(int i=2;i<=n;i++){
    35         scanf("%d%d",&fa[i],&x);
    36         ch[fa[i]][x]=i;
    37     }
    38     dfs(1);
    39     
    40     for(ll i=1;i<=top;i++) st[i]=st[i]-i;
    41     
    42     q[0]=-10000000000;
    43     for(int i=1;i<=top;i++) run(st[i]);
    44     
    45     int ans=n-rear;
    46     printf("%d",ans);
    47 }
    48 int main(){
    49     init();
    50     
    51     return 0;
    52 }

    将序列改成严格单调增想到最大化不变的数,但直接LIS求的是改为非严格单调增的数

    一个将严格单调增问题改为非严格的套路是将数aiai替换成aiiai−i,对转换后序列求LIS即可

    (其实也可以理解为在严格单增问题中能拓展的条件为a[i]a[k]ika[i]−a[k]≥i−k,那么也就是a[i]ia[k]ka[i]−i≥a[k]−k)

    B:

    长度可行性单调,对长度二分答案

    发现区间[l,r][l,r]中存在kk的条件为:gcd(l...r)=min(l...r)=kgcd(l...r)=min(l...r)=k

    区间最小和gcdgcd明显可以用RMQRMQ维护,但此题卡log2log2,因此只能用STST表来维护

     1 #include<bits/stdc++.h>
     2 #define maxn 500005
     3 using namespace std;
     4 int n,a[maxn],np=0,rt=0;
     5 int gcd(int x,int y){
     6     if(y==0) return x;
     7     else return gcd(y,x%y);
     8 }
     9 int minv[maxn][20],gcdd[maxn][20],logg[maxn],w[25];
    10 void ready(){
    11     w[0]=1;
    12     logg[0]=-1;
    13     for(int i=1;i<=20;i++) w[i]=w[i-1]*2;
    14     for(int i=1;i<=maxn-5;i++) logg[i]=logg[i/2]+1;
    15     for(int i=1;i<=n;i++){
    16         minv[i][0]=gcdd[i][0]=a[i];
    17     }
    18     for(int i=1;i<=logg[n];i++)//加个1保个险 
    19     for(int j=1;j<=n;j++)
    20     if(j+w[i]-1<=n){
    21         minv[j][i]=min(minv[j][i-1],minv[j+w[i-1]][i-1]);//本来是j+(1<<(i-1))-1+1
    22         gcdd[j][i]=gcd(gcdd[j][i-1],gcdd[j+w[i-1]][i-1]);
    23     } 
    24 }
    25 int cd1(int i,int j){
    26     int len=j-i+1;
    27     int t=logg[len];
    28     return min(minv[i][t],minv[j-w[t]+1][t]);
    29 }
    30 int cd2(int i,int j){
    31     int len=j-i+1;
    32     int t=logg[len];
    33     return gcd(gcdd[i][t],gcdd[j-w[t]+1][t]);
    34 }
    35 int st[maxn],top=0,yb[maxn],topp=0;
    36 bool check(int mid){
    37     topp=0;
    38     bool ok=false;
    39     for(int i=1;i<=n-mid+1;i++){
    40         int j=i+mid-1;
    41         if(cd1(i,j)==cd2(i,j)){
    42             ok=true;
    43             yb[++topp]=i;
    44         }
    45     }
    46     if(ok){
    47         top=0;
    48         for(int i=1;i<=topp;i++) st[++top]=yb[i];
    49         return true;
    50     }
    51     return false;
    52 }
    53 void run(){
    54     int A=1,B=n,mid,ans;
    55     while(A<=B){
    56         mid=A+B>>1;
    57         if(check(mid))
    58         ans=mid,A=mid+1;
    59         else B=mid-1;
    60     }
    61     printf("%d %d
    ",top,ans-1);//L-R
    62     for(int i=1;i<=top;i++) printf("%d ",st[i]);
    63 } 
    64 void init(){
    65     scanf("%d",&n);
    66     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    67     ready(); 
    68     run(); 
    69 }
    70 int main(){
    71     init();
    72     
    73     return 0;
    74 }

    如果只有询问用STST表O(1)O(1)询问

    同时注意由于对一个数多次求gcdgcd不会影响区间gcdgcd值,因此可以直接用STST表维护gcdgcd

    C:

    很像以前冒泡排序相关题的一个TrickTrick:

    由于交换序列是一个排列,因此每次交换后左右不可能再有交换,这样就拆为独立的子问题了

    由于初始状态的值有规律是单调的,因此反向考虑问题:

    对于当前区间[l,r][l,r]枚举交换位置ii,如果交换i,i+1i,i+1后左序列是[l,l+i1][l,l+i−1]的一个排列则计算其贡献

    dp[l][r]=dp[l][l+i1]dp[l+i][r]Ci1rl+12dp[l][r]=dp[l][l+i−1]∗dp[l+i][r]∗Cr−l+1−2i−1

     1 #include<bits/stdc++.h>
     2 #define maxn 55
     3 using namespace std;
     4 typedef long long ll;
     5 const ll mod=1e9+7;
     6 ll c[maxn][maxn],dp[maxn][maxn];
     7 int p[maxn],n;
     8 void ready(){
     9     for(int i=0;i<=50;i++){
    10         c[i][0]=1;
    11         for(int j=1;j<=i;j++)
    12         c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
    13     }
    14 }
    15 ll dfs(int len,int now){
    16     if(dp[len][now]!=-1) return dp[len][now];
    17     if(len==1) return dp[len][now]=1;
    18     ll ans=0;int j,k,pos=0,t[maxn];//pos和t只有内定了给,不然要重 函数递归时会改变 
    19     for(int i=1;i<=n;i++)
    20     if(p[i]>=now&&p[i]<now+len) t[++pos]=p[i];//pos==len
    21     for(int i=1;i<pos;i++){
    22         swap(t[i],t[i+1]);//枚举交换的位置
    23         for(j=1;j<=i;j++)//判断是否满足
    24         if(t[j]>=now+i) break;//最多为now+i-1;
    25         for(k=i+1;k<=pos;k++)
    26         if(t[k]<now+i)  break;//最小为now+i; 
    27         if(j>i&&k>pos){
    28             ll t1=dfs(i,now);
    29             ll t2=dfs(pos-i,now+i);
    30             ans=(ans+t1*t2%mod*c[pos-2][i-1]%mod)%mod;//第一个:now~now+i-1 第二个now+i~now+len-1; 
    31                                     //在这之前进行n-2次交换,前i-1次选择前面来处理前面的i个 
    32         }
    33         swap(t[i],t[i+1]);
    34     }
    35     return dp[len][now]=ans; 
    36 }
    37 void init(){
    38     scanf("%d",&n);
    39     for(int i=1;i<=n;i++) scanf("%d",&p[i]);
    40     memset(dp,-1,sizeof(dp));
    41     dfs(n,0);
    42     if(dp[n][0]==-1) printf("%d",0);
    43     else printf("%lld",dp[n][0]);
    44 }
    45 int main(){
    46     ready();
    47     init();
    48     
    49     return 0;
    50 }

    注意这里每次处理的[l,r][l,r]的排列是pp的子序列!

    (处理到该子问题时能保证数在pp中的相对位置不变)

    D:

    关键在于贡献为2R+C2R+C,可以理解为对每一个子集算一次贡献

    接下来算每个集合被包含的期望次数即可:

    res=CinCjnCknummnumCkmres=∑Cni∗Cnj∗Cm−numk−numCmk

    其中numnum为如果ii行jj列全涂黑的个数,预处理组合数即可

     1 #include<bits/stdc++.h>
     2 #define maxn 305
     3 using namespace std;
     4 int n,m,k;
     5 double a[maxn],b[maxn*maxn];//b:(k-x,m-x)/(k,m) 而x最多为n^2
     6 void ready(){
     7     a[0]=1.0;
     8     for(int i=1;i<=n;i++) a[i]=a[i-1]*(n-i+1)*1.0/i;
     9     b[0]=1;
    10     for(int i=1;i<=n*n;i++) b[i]=b[i-1]*(k-i+1)*1.0/(m-i+1); 
    11 } 
    12 void outt(){
    13     printf("1");
    14     for(int i=1;i<=99;i++) printf("0");
    15 }
    16 int main(){
    17     scanf("%d%d%d",&n,&m,&k);
    18     ready();
    19     double ans=0;
    20     for(int i=0;i<=n;i++)
    21     for(int j=0;j<=n;j++){
    22         int x=(i+j)*n-i*j;
    23         if(x>k) break;//再加只会更多 
    24         ans+=a[i]*a[j]*b[x];
    25     } 
    26     if(ans>1e99) outt();
    27     else printf("%lf",ans);
    28     
    29     return 0;
    30 } 
  • 相关阅读:
    668. Kth Smallest Number in Multiplication Table
    658. Find K Closest Elements
    483. Smallest Good Base
    475. Heaters
    454. 4Sum II
    441. Arranging Coins
    436. Find Right Interval
    410. Split Array Largest Sum
    392. Is Subsequence
    378. Kth Smallest Element in a Sorted Matrix
  • 原文地址:https://www.cnblogs.com/degage/p/9683558.html
Copyright © 2011-2022 走看看