zoukankan      html  css  js  c++  java
  • [考试反思]0305省选模拟38:存在

    然而今天没有第二张图。 因为我并没有上榜。。。

    离考试结束还有$10$分钟左右的时候开始尝试提交,然后断网了。

    然后连了$10$分钟没连上,然后就硬核爆零了。

    如果交上去的话,打的都打满了,$24+27+40=91$.是$rk9$

    好不到哪里去。。反正是被这个网严重影响了心情。

    $T1$大概想到了正解思路但是中途网断了,重连时候就没有按照原来的思路想下去。

    $T2$一眼发现大概是原题,于是开始想,大概有印象但是具体内容忘掉了,所以打了暴力就走了。

    $T3$想到了正解的一部分,但是因为时间不够以及网络问题没有继续深究,拿着比较丰厚的$40$暴力就走了。

    然后这么简单的一次考试我就爆零了。。。

    其实今天状态也不太好,有一点头晕&困。然后下午就集中爆发了。

    大概在晚上恢复了状态,压着时间把三道题都改出来了(得亏题目简单。。。)

    话说仨题两个前缀和一个差分,出题人想表达什么。。?

    T1:inverse

    大意:排列,$k$次操作等概率翻转一个区间。求最终逆序对数的期望。$n le 500,k le 50$

    我转化成方案数来统计了,一样的。

    设$dp_{i,j,k}$表示$i$轮后$P_j > P_k$的方案数。枚举翻转区间暴力来复杂度是$O(kn^4)$的

    然后我们分情况讨论,讨论翻转的区间包含了哪个端点,4种情况,每种的转移点数量都是不超过$O(n)$的,所以复杂度是$O(kn^3)$

    然后我们把转移式子继续化简,发现可以使用前缀和优化,还是二维的,所以多弄几个行,列,斜线的前缀和优化,时间复杂度就是$O(kn^2)$的了

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define mod 1000000007
     4 #define cl(s) memset(s,0,sizeof s)
     5 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;}
     6 int mo(int a){return a>=mod?a-mod:a;}
     7 int px(int x){return x*(x+1)>>1;} 
     8 int n,k,p[555],dp[501][501],ans,s1[505][505],s2[505][505],s3[505][505],s4[505][505],s5[505][505],s6[505][505];
     9 int main(){
    10     scanf("%d%d",&n,&k);
    11     for(int i=1;i<=n;++i)scanf("%d",&p[i]);
    12     for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)dp[i][j]=p[i]>p[j];
    13     for(int o=1,pl=1;o<=k;++o){
    14         for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)
    15             s1[i][j]=mo(s1[i][j-1]+dp[i][j]),s2[i][j]=mo(s2[i][j-1]+s1[i][j]),
    16             s3[i][j]=mo(s3[i-1][j]+dp[i][j]),s4[i][j]=mo(s4[i-1][j]+s3[i][j]),
    17             s5[i][j]=mo(s5[i-1][j-1]+dp[i][j]),s6[i][j]=mo(s6[i-1][j-1]+s5[i][j]);        
    18         for(int i=1;i<=n;++i)for(int j=i+1;j<=n;++j)
    19             dp[i][j]=dp[i][j]*(0ll+px(i-1)+px(j-i-1)+px(n-j))%mod,
    20             dp[i][j]=(0ll+dp[i][j]+s4[j-1][j]-s4[j-i-1][j]-s4[i-1][j]+mod+mod)%mod,
    21             dp[i][j]=(0ll+dp[i][j]+s2[i][n]+s2[i][i-1]-s2[i][n+i-j]-s2[i][j-1]+mod+mod)%mod,
    22             dp[i][j]=(0ll+dp[i][j]+s6[n][n+i-j]-s6[n-i][n-j]-s6[j-1][i-1]+mod+mod)%mod;
    23         pl=1ll*pl*px(n)%mod;
    24         for(int i=1;i<=n;++i)for(int j=1;j<i;++j)dp[i][j]=mo(mod+pl-dp[j][i]);
    25     }
    26     for(int i=1;i<=n;++i)for(int j=i+1;j<=n;++j)ans=mo(ans+dp[i][j]);
    27     printf("%lld
    ",1ll*ans*qp(qp(px(n),k),mod-2)%mod);
    28 }
    View Code

    T2:Subsequence

    大意:数列$A$,对于所有长度$k in [1,n]$求一个长为$k$的子序列$B$,最大化$sumlimits_{i=1}^{k} i imes B_i$。$n le 100000$

    原题链接

    不一样的地方在于这次必须是子序列,不能乱序。所以把排序去掉就好了。

    还是决策单调性,平衡树维护差分$dp$数组,依次插入每个数,然后是区间加之类的。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 123456
     4 int n,c[2][S],f[S],sz[S],s[S],rt,pc;long long Ans,lz[S],w[S],a[S];
     5 #define lc c[0][p]
     6 #define rc c[1][p]
     7 void up(int p){sz[p]=sz[lc]+sz[rc]+1;}
     8 void down(int p){lz[lc]+=lz[p];lz[rc]+=lz[p];w[lc]+=lz[p];w[rc]+=lz[p];lz[p]=0;}
     9 void spin(int p){
    10     int F=f[p],G=f[F],d=c[1][F]==p,B=c[!d][p];
    11     if(G)c[c[1][G]==F][G]=p; c[d][c[!d][p]=F]=B;
    12     if(B)f[B]=F; f[f[F]=p]=G; up(F); up(p);
    13 }
    14 void splay(int p){
    15     int F=p,t=0; while(F)s[++t]=F,F=f[F]; while(t)down(s[t--]);
    16     for(;F=f[p];spin(p))if(f[F])spin(c[1][f[F]]==F^c[1][F]==p?p:F); rt=p;
    17 }
    18 void insert(int p){
    19     int lp,d,Sz=1;
    20     while(p){
    21         down(lp=p);
    22         if(w[p]>a[pc]*(Sz+sz[lc]))Sz+=sz[lc]+1,d=1;
    23         else d=0;p=c[d][p];
    24     }
    25     p=pc; c[d][f[p]=lp]=p; w[p]=a[p]*Sz; splay(p);
    26     w[rc]+=a[p]; lz[rc]+=a[p];
    27 }
    28 void dfs(int p){
    29     if(!p)return; down(p);
    30     dfs(lc); Ans+=w[p]; printf("%lld ",Ans); dfs(rc);
    31 }
    32 int main(){
    33     scanf("%d%lld",&n,&a[1]);
    34     rt=sz[1]=pc=1;w[1]=a[1];
    35     for(pc=2;pc<=n;++pc)scanf("%lld",&a[pc]),insert(rt);
    36     dfs(rt);
    37 }
    View Code

    T3:Convex

    大意:凸多边形,求按照每条对角线划分后两部分面积差绝对值之和的2倍。$n le 2 imes 10^6$

    暴力的做法是枚举对角线嘛。

    不那么暴力的话我们发现我们可以只枚举一个端点,然后我们可以找到一个分界点,顺时针方向都是对角线上方的比较大,逆时针则小。

    判断的条件是面积是否超过整个多边形的一半。因为是凸多边形所以随着你枚举的点递增分界点也递增,单调指针就好了。

    得到分界点,问题在于求出若干多边形面积的和。

    考虑多边形面积如何计算:三角剖分。这道题里为了让不同的边之间没有关联,我们围绕原点进行三角剖分。

    也就是说某个多边形面积等于它在原多边形上,直线与每对相邻的两点相连,得到的两个向量的叉积。

    所以问题就转化到了相邻的点对上。发现如果当前枚举点为$x$而分界点是$y$那么$(0,0)-> y-1 imes (0,0) -> y$这对向量叉积累加答案一次。

    $(y-2,y-1)$累加$2$次。。。$(x,x+1)$累加$y-x$次。是等差数列。所以维护前缀和的前缀和,加加减减就好了。

    这是在原凸多边形上相邻的两个点做出的贡献,通过预处理解决了。

    剩下没有考虑的就是对角线两点的贡献。发现当你枚举的点确定是,另一个点是连续的。

    你大概要求一个$sumlimits_{i=x}^{y} x_x y_i - y_x x_i$。很明显的前缀和形式,维护横纵坐标的前缀和就好了。

    既然已经得到了分界点以及一堆面积小于一半的多边形的面积,那么剩下的就都可以大概同理的求出来了。

    然后加一些取模优化啥的不然可能被卡常。。大概是没了。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 6222222 
     4 #define mod 1000000007
     5 long long s[S],s2[S],s1[S],X[S],Y[S],ans,ss,x[S],y[S];int n;
     6 long long cross(int a,int b){return x[a]*y[b]-x[b]*y[a];}
     7 long long cal(int a,int b){if(b>n)b-=n;return cross(a,b)+s[b-1]-s[a-1]+(a<b?0:s[n]);}
     8 int read(){
     9     register char ch=getchar();register int p=0,f=0;
    10     while(!isdigit(ch))f=ch=='-',ch=getchar();
    11     while(isdigit(ch))p=p*10+ch-48,ch=getchar();
    12     return f?-p:p;
    13 }
    14 int mo(int a){return a<0?a+mod:(a>=mod?a-mod:a);}
    15 int main(){
    16     scanf("%d",&n);
    17     for(int i=1;i<=n;++i)x[i]=read(),y[i]=read(),x[n+i]=x[i],y[n+i]=y[i];
    18     for(int i=1;i<=n;++i)s[i]=s[i-1]+cross(i+1,i);
    19     for(int i=1;i<=n+n;++i)s1[i]=(s1[i-1]+cross(i+1,i))%mod,s2[i]=mo(s2[i-1]+s1[i]),X[i]=mo(X[i-1]+x[i]),Y[i]=mo(Y[i-1]+y[i]);
    20     ss=s[n]%mod;int pt=3;
    21     for(int i=1;i<=n;++i){
    22         while(cal(i,pt+1)<=s[n]>>1)pt++;
    23         long long a1=mo((s2[pt-1]-s2[i-1]-s1[i-1]*(pt-i))%mod+mod),a2=mo((s2[i+n-3]-s2[i-1]-s1[i-1]*(n-2))%mod+mod);
    24         a1+=x[i]*(Y[pt]-Y[i-1])-y[i]*(X[pt]-X[i-1]);
    25         a2+=x[i]*(Y[i+n-2]-Y[i-1])-y[i]*(X[i+n-2]-X[i-1]);
    26         a2-=a1;
    27         ans=(ans+ss*(pt-i-1)-2*a1+2*a2-ss*(n-3-(pt-i-1)))%mod;
    28     }printf("%lld
    ",(ans+mod)%mod*500000004ll%mod);
    29 }
    View Code
  • 相关阅读:
    oracle锁---原理篇
    SML + NL + HJ
    Oracle中varchar,varchar2,nvarchar,nvarchar2的区别
    oracle 一致读原理
    commit 流程
    IMPDP NETWORK_LINK参数
    WINDOWS访问虚拟机RedHat搭配的Apache2服务器
    初识malloc函数
    好吧,又失眠
    休息一天
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12423766.html
Copyright © 2011-2022 走看看