2021 10.26 模擬測試
阿新 • • 發佈:2021-10-27
\(\mathrm{T1}\)
\(\mathrm{Solution}\)
我們可以記錄一個\(cnt[x]\)表示到第\(i\)個操作要讓答案是\(x\)的最小運算元。
顯然對於操作1等同於將\(cnt[p]\)清零,將除\(p\)以外的所有\(cnt++\)
而對於操作2則是將\(cnt[q]\)更新為\(\min(cnt[p],cnt[q])\),而\(cnt[p]++\)
但這樣做是\(O(n^2)\)的,所以只需要把操作1的區間加法優化為O(1)即可
#include<bits/stdc++.h> #define fi first #define se second #define in read() using namespace std; inline int read() { int data=0,w=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if(ch=='-') w=-1,ch=getchar(); while(ch>='0'&&ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar(); return data*w; } inline void write(int x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+48); } const int N=1e7+5; int n,lzy; int cnt[N],lazy[N]; int main() { //freopen("order.in","r",stdin); //freopen("order.out","w",stdout); n=in; memset(cnt,-1,sizeof(cnt)); cnt[1]=0; for(int i=1;i<=n;i++) { int op=in; if(op==1) { lzy++; // for(int i=1;i<=n;i++) // if(~cnt[i]) cnt[i]++; int p=in; cnt[p]=0;lazy[p]=lzy; } if(op==2) { int p=in,q=in; if(~cnt[p]&&((cnt[q]+lzy-lazy[q])>(cnt[p]+lzy-lazy[p])||cnt[q]==-1)) cnt[q]=cnt[p],lazy[q]=lazy[p]; if(~cnt[p]) cnt[p]++; } // cout<<1<<'\n'; // cout<<cnt[2]<<'\n'; } for(int i=1;i<=n;i++) //write(cnt[i]),putchar(' '); write(~cnt[i]?cnt[i]+lzy-lazy[i]:-1),putchar(' '); } /* 5 2 1 4 1 3 2 3 5 1 2 1 5 */
\(\mathrm{T2}\)
\(\mathrm{Solution}\)
對於暴力列舉點是\(O(n^2)\)的,但是發現每一個點對答案的貢獻只有自己的度數減去與其他點的連的邊的個數,而度數最多隻有\(\sqrt{m}\)個,所以如果我們先不考慮重邊而去列舉度數的話效率是\(O(m)\)的,最後在列舉點去把重複的點刪掉即可
效率\(O(n+m)\)
為什麼最多隻有\(\sqrt{m}\)個呢,因為對於所有點來說度數之和為\(2m\),而最壞情況就是\(1+2+……+k=2m\),解得\(k\)約等於\(\sqrt{m}\)
#include<bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define mp make_pair #define int long long #define in read() using namespace std; inline int read() { int data=0,w=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if(ch=='-') w=-1,ch=getchar(); while(ch>='0'&&ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar(); return data*w; } inline void write(int x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+48); } const int N=1e6+5; int n,m,Q,rd[N],t[N]; int a[N<<1]; vector<int>e[N]; vector<pii>c; signed main() { n=in,m=in; for(int i=1,u,v;i<=m;i++) { u=in,v=in; e[u].push_back(v); if(u!=v) e[v].push_back(u); } for(int i=1;i<=n;i++) t[rd[i]=e[i].size()]++; for(int i=0;i<=m;i++) if(t[i]>0) c.push_back(mp(i,t[i])); for(int i=0;i<c.size();i++) for(int j=i;j<c.size();j++) if(i==j) a[c[i].fi+c[i].fi]+=(c[i].se*(c[i].se-1))>>1; else a[c[i].fi+c[j].fi]+=c[i].se*c[j].se; for(int u=1;u<=n;u++) { static int cnt[N]; for(int v:e[u]) if(v<u) cnt[v]++; for(int v:e[u]) if(cnt[v]) { a[rd[u]+rd[v]]--; a[rd[u]+rd[v]-cnt[v]]++; cnt[v]=0; } } for(int i=m<<1;~i;--i) a[i]+=a[i+1]; Q=in; while(Q--) write(a[in+1]),puts(""); }
\(\mathrm{T3}\)
\(\mathrm{Solution}\)
設\(dp[i][mov]\)表示考慮第\(i\)個到第\(n\)個操作,能有至少一次到當前位置\(+mov\)的概率
轉移即
\[dp[i][mov]+=p\times dp[i+1][mov] \]\[dp[i][mov+a[i]]+=(1-p)\times dp[i+1][mov] \]\[dp[i][0]=1 \]最後\(dp[1][i]\)就是答案
#include<bits/stdc++.h> #define in read() using namespace std; inline int read() { int data=0,w=1; char ch=getchar(); while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); if(ch=='-') w=-1,ch=getchar(); while(ch>='0'&&ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar(); return data*w; } inline void write(int x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); } const int mod=998244353; const int N=5e3+5; const int _100=828542813; int n,p,a[N]; int f[N][N<<1]; inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;} inline int mul(int a,int b){return (1ll*a*b)%mod;} inline int dec(int a,int b){return a-b<0?a-b+mod:a-b;} void solve() { f[n+1][N]=1;int l=0,r=0; for(int i=n;i;--i) { a[i]==1?r++:l++; for(int j=N-l;j<=N+r;j++) { f[i][j]=add(f[i][j],mul(p,f[i+1][j])); f[i][j+a[i]]=add(f[i][j+a[i]],mul(dec(1,p),f[i+1][j])); } f[i][N]=1; } for(int i=N-n;i<=N+n;i++) write(f[1][i]),puts(""); } int main() { n=in,p=mul(in,_100); for(int i=1;i<=n;i++) a[i]=in; puts("0");solve(); }