noip多校模擬28
阿新 • • 發佈:2021-11-11
考試過程:這次考試,感覺不在狀態。四個題都沒有什麼正解的思路,心態也比較不好。
總體來說今天的狀態不是很好,需要及時調整。
T1 嗑瓜子
因為我幾天前做了一道期望題,那個題是資料範圍也是比較小,而且正解是\(o(n)\)的,所以這道題我也就一直在想\(o(n)\)的做法,想了一個多小時,沒什麼思路,就直接棄了。但是正解是\(o(n^2)\)的。
剛開始我設\(f_{i,j}\)表示我拿了\(i\)個瓜子,\(j\)個瓜子皮的期望次數,但是得到的結果不對,然後根據定義顯然沒法轉移,因為我拿\(i\)個瓜子,\(j\)個瓜子皮的期望次數顯然就是\(i+j\)次,所以這樣正推不可行。
於是設\(f_{i,j}\)
最後還有注意的一點,題目要求輸出\(q\times r\)與\(p\)同餘,那麼也就是\(r\)與\(\frac{p}{q}\)同餘,也就是\(p\times inv[q]\)
程式碼如下:
AC_code
#include<bits/stdc++.h>
#define int long long
#define re register int
#define ii inline int
#define iv inline void
using namespace std;
const int mo=998244353;
const int N=2e3+10;
const int M=1e4+10;
int n,ans;
int f[N][N<<1],jc[M],pv[M],inv[M];
ii read()
{
int x=0; char ch=getchar(); bool f=1;
while(ch<'0' or ch>'9')
{
if(ch=='-') f=0;
ch=getchar();
}
while(ch>='0' and ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return f?x:(-x);
}
ii ksm(int d,int z)
{
int out=1;
while(z)
{
if(z&1) out=out*d%mo;
z>>=1;
d=d*d%mo;
}
return out;
}
signed main()
{
freopen("eat.in","r",stdin);
freopen("eat.out","w",stdout);
n=read();
if(n==1) {printf("1\n");return 0;}
jc[0]=1;
for(re i=1;i<M;i++) jc[i]=jc[i-1]*i%mo;
pv[M-1]=ksm(jc[M-1],mo-2);
for(re i=M-2;i>=0;i--) pv[i]=pv[i+1]*(i+1)%mo;
inv[0]=1;
for(re i=1;i<M;i++) inv[i]=pv[i]*jc[i-1]%mo;
for(re i=1;i<=n;i++) for(re j=0;j<=(n-i)*2;j++) f[i][j]=(j*inv[i+j]%mo*f[i][j-1]%mo+i*inv[i+j]%mo*f[i-1][j+2]%mo+1ll)%mo;
printf("%lld\n",f[n][0]);
return 0;
}
T2 第k大查詢
思路:
如果我們找到朝左和朝右k個比它大的元素,那麼一個個元素是第\(k\)當且僅當個包含了\(k-1\) 個比它大的元素,可以在\(o(k)\) 時間複雜度內解決。如何找到往左往右比它大的\(k\)個元素,我們可以把元素用雙向連結串列連線起來,每次刪除一個元素的時候往左往右找即可。
程式碼如下:
AC_code
#include<bits/stdc++.h>
#define int long long
#define re register int
#define ii inline int
#define iv inline void
using namespace std;
const int N=5e5+10;
int n,k,ans;
int pre[N],suf[N];
int a[N],pos[N],u1[N],u2[N];
ii read()
{
int x=0; char ch=getchar(); bool f=1;
while(ch<'0' or ch>'9')
{
if(ch=='-') f=0;
ch=getchar();
}
while(ch>='0' and ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return f?x:(-x);
}
signed main()
{
freopen("kth.in","r",stdin);
freopen("kth.out","w",stdout);
n=read(),k=read();
for(re i=1;i<=n;i++) a[i]=read(),pos[a[i]]=i;
int p=pos[1];
for(re i=1;i<=n;i++) pre[i]=i-1,suf[i]=i+1;
for(re i=1;i<=n;i++)
{
int l=0,r=0;
for(re j=pos[i];j and l<k;j=pre[j]) u1[l++]=j-pre[j];
for(re j=pos[i];j<=n and r<k;j=suf[j]) u2[r++]=suf[j]-j;
for(re j=0;j<l;j++) if(k-j-1<r) ans=ans+i*u1[j]*u2[k-j-1];
suf[pre[pos[i]]]=suf[pos[i]];
pre[suf[pos[i]]]=pre[pos[i]];
pre[pos[i]]=suf[pos[i]]=0;
}
printf("%lld\n",ans);
return 0;
}