Noip模擬4(忁靈霽) 2021.6.6
T1 隨(Rand)
給出n個正整數a1,a2…an和一個質數mod.一個變數x初始為1.進行m次操作.每次在n個數中隨機選一個ai,然後 x=x∗ai%modx=x*a_i \%modx=x∗ai%mod.問m次操作之後x的取值的期望. 答案一定可以表示成a/b a/ba/b的精確分數形式.a和b可能很大,所以只需要輸出a∗(b(109+5)) a*(b^{(10^9+5)})a∗(b(109+5))模109+710^9+7109+7的結果.
第一行三個整數n,m,mod. 接下來一行n個空格隔開的正整數a1,a2…an
一行一個整數表示答案
樣例輸入
2 1 3
1 2
樣例輸出
500000005
由槓哥大定理可得,這題目前不可做,先跳走啦,咕咕。。。。
T2 單(single)
單車聯通大街小巷.這就是出題人沒有寫題目背景的原因. 對於一棵樹,認為每條邊長度為1,每個點有一個權值a[i].dis(u,v)為點u到v的最短路徑的邊數.dis(u,u)=0.對每個點求出一個重要程度.點x的重要程度b[x]定義為其他點到這個點的距離乘上對應的點權再求和. 即:b[x]=a[1]dis(1,x)+a[2]dis(2,x)+....+a[n]*dis(n,x) 現在有很多樹和對應的a陣列,並求出了b陣列.不幸的是,記錄變得模糊不清了.幸運的是,樹的形態完好地儲存了下來,a陣列和b陣列至少有一個是完好無損的,但另一個數組完全看不清了. 希望你求出受損的陣列.多組資料.
第一行輸入一個T,表示資料組數。接下來T組資料。 每組資料的第1行1個整數n表示樹的點數.節點從1到n編號. 接下來n-1行每行兩個整數u,v表示u和v之間有一條邊. 接下來一行一個整數t,表示接下來陣列的型別。 t=0則下一行是a陣列,t=1則下一行是b陣列。 接下來一行n個整數,表示儲存完好的那個陣列,第i個數表示a[i]或b[i]。
T行,每組資料輸出一行表示對應的a陣列或b陣列,陣列的相鄰元素用一個空格隔開。忽略行末空格和行尾回車.
樣例輸入
2
2
1 2
1
17 31
2
1 2
0
31 17
樣例輸出
31 17
17 31
對於100%的資料,T=5, 2<=n<=100000,1<=u,v<=n,保證給出的n-1條邊形成一棵樹 對於100%的資料,t=0或t=1,1<=a[i]<=100,1<=b[i]<=10^9,t=1時保證給出的b陣列對應唯一的一個a陣列。 對於100%的資料,單個輸入檔案不會包含超過2000000個整數,這段話可以理解為,你不必考慮輸入輸出對程式執行時間的影響。 對於100%的資料,保證答案不會超過int能表示的範圍
考場上,簡單看一眼就看出是個高斯消元,然後。。。。。
板子沒記住!!!
然而這不是最糟糕的。。。。
執著的我進行了對高斯消元的推演與執行,在大把時間荒廢后,發現自己終於將樣例中的一半答對了!!
然而,考試接近了尾聲,匆匆地蒙了下其他幾個題的答案就結束了。。。
然而,高斯消元推假了。。。。
就這樣達成成就———爆〇!!
其實上,這題做法比較多(部分分數),然而 這題的ac程式碼是dfs。看了題解之後思路清晰展了,很快碼完,但想想這題思維量,考上上暫時還做不到呢。。。。。
正確思路:
t=0的時候知道a陣列,這時候可以求出所有點到根(1)的距離,這樣可以生猛的算出b[1],
接著找(1)和他兒子們的關係,列出表示式發現以兒子(2)為根點的子樹上對(2)的距離(稱為貢獻)都少了1,
於是,我們記錄一個size陣列表示以i為根節點的子樹上的點權和
由於父子間的關係可以推出b[son]=b[fa]+size[1]-2*size[son];
dfs一遍就可以求出b;
t=1時,將上面柿子移項可得b[son]-b[fa]=size[1]-2*size[son];
插一句嘴,我們可以發現b[1]=size[2]+size[3]+size[4]+...+size[n]
就和之前的那個概率期望的神仙推柿子題一樣,將size展開然後合併同類項發現每個點加的次數都為那個點的深度減一,及到根節點距離;
將c[i]=size[1]-2*size[i]; i!=1;
將除了c[1]的c陣列加和得: tot=(n-1)size[1]-2*(size[2]+size[3]+...+size[n])
嘔吼,可以化簡了!! tot=(n-1)size[1]-2*b[1];
這樣,原本未知的size便可以求了 size[i]=(size[1]-c[i])/2
求出size,將size倒著求a就可以知道a是啥了;
這種思維量大的題不多見,考場上還是要仔細思考,別放過任何一點新奇的想法,才有可能想對吧。。。。
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 const int NN=1e5+5; 5 int T,n,dis[NN],a[NN],b[NN],size[NN],c[NN]; 6 struct SNOW{ 7 int to,next; 8 }; SNOW e[NN<<1]; int r[NN<<1],tot; 9 inline void add(int x,int y){ 10 e[++tot]=(SNOW){y,r[x]}; 11 r[x]=tot; 12 } 13 inline void dfs(int fa,int x){ 14 for(int i=r[x];i;i=e[i].next) 15 if(e[i].to!=fa){ 16 dis[e[i].to]=dis[x]+1; 17 dfs(x,e[i].to); 18 } 19 } 20 inline void dfs1(int fa,int x){ 21 for(int i=r[x];i;i=e[i].next) 22 if(e[i].to!=fa){ 23 dfs1(x,e[i].to); 24 size[x]+=size[e[i].to]; 25 } 26 } 27 inline void dfs2(int fa,int x){ 28 for(int i=r[x];i;i=e[i].next) 29 if(e[i].to!=fa){ 30 b[e[i].to]=b[x]+size[1]-2*size[e[i].to]; 31 dfs2(x,e[i].to); 32 } 33 } 34 inline void dfs3(int fa,int x){ 35 for(int i=r[x];i;i=e[i].next) 36 if(e[i].to!=fa){ 37 c[e[i].to]=a[e[i].to]-a[x]; 38 dfs3(x,e[i].to); 39 } 40 } 41 inline void dfs4(int fa,int x){ 42 for(int i=r[x];i;i=e[i].next) 43 if(e[i].to!=fa){ 44 b[e[i].to]=size[e[i].to]=(size[1]-c[e[i].to])/2; 45 dfs4(x,e[i].to); 46 } 47 } 48 inline void dfs5(int fa,int x){ 49 for(int i=r[x];i;i=e[i].next) 50 if(e[i].to!=fa){ 51 dfs5(x,e[i].to); 52 b[x]-=size[e[i].to]; 53 } 54 } 55 inline int read(){ 56 int x=0,f=1; char ch=getchar(); 57 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 58 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 59 return x*f; 60 } 61 namespace WSN{ 62 inline int main(){ 63 T=read(); 64 while(T--){ 65 memset(b,0,sizeof(b)); 66 memset(c,0,sizeof(c)); 67 memset(size,0,sizeof(size)); 68 memset(dis,0,sizeof(dis)); 69 memset(r,0,sizeof(r)); tot=0; 70 n=read(); 71 for(int i=1;i<n;i++){ 72 int x=read(),y=read(); 73 add(x,y); add(y,x); 74 } 75 int t=read(); 76 for(int i=1;i<=n;i++) a[i]=read(); 77 if(!t){ 78 dfs(0,1); 79 for(int i=2;i<=n;i++) b[1]+=dis[i]*a[i]; 80 for(int i=1;i<=n;i++) size[i]=a[i]; 81 dfs1(0,1); 82 dfs2(0,1); 83 for(int i=1;i<=n;i++) printf("%lld ",b[i]); 84 putchar('\n'); 85 } 86 if(t){ 87 dfs3(0,1); int cnt=0; 88 for(int i=2;i<=n;i++) cnt+=c[i]; 89 size[1]=(cnt+2*a[1])/(n-1); 90 dfs4(0,1); 91 dfs5(0,1); 92 b[1]=size[1]; 93 for(int i=2;i<=n;i++) b[1]-=b[i]; 94 for(int i=1;i<=n;i++) printf("%lld ",b[i]); 95 putchar('\n'); 96 } 97 } 98 return 0; 99 } 100 } 101 signed main(){return WSN::main();}View Code
然而,六個dfs就很淦,感覺打完這道題對xin_team的理解又加深了不少呢
T3 題(problem)
你在平面直角座標系上. 你一開始位於(0,0). 每次可以在上/下/左/右四個方向中選一個走一步. 即:從(x,y)走到(x,y+1),(x,y-1),(x-1,y),(x+1,y)四個位置中的其中一個. 允許你走的步數已經確定為n.現在你想走n步之後回到(0,0).但這太簡單了.你希望知道有多少種不同的方案能夠使你在n步之後回到(0,0).當且僅當兩種方案至少有一步走的方向不同,這兩種方案被認為是不同的. 答案可能很大所以只需要輸出答案對10^9+7取模後的結果.(10^9+7=1000000007,1和7之間有8個0) 這還是太簡單了,所以你給能夠到達的格點加上了一些限制.一共有三種限制,加上沒有限制的情況,一共有四種情況,用0,1,2,3標號: 0.沒有任何限制,可以到達座標系上所有的點,即能到達的點集為{(x,y)|x,y為整數} 1.只允許到達x軸非負半軸上的點.即能到達的點集為{(x,y)|x為非負數,y=0} 2.只允許到達座標軸上的點.即能到達的點集為{(x,y)|x=0或y=0} 3.只允許到達x軸非負半軸上的點,y軸非負半軸上的點以及第1象限的點.即能到達的點集為{(x,y)|x>=0,y>=0}
一行兩個整數(空格隔開)n和typ,分別表示你必須恰好走的步數和限制的種類.typ的含義見【題目描述】.
一行一個整數ans,表示不同的方案數對10^9+7取模後的結果.
【樣例輸入0】
100 0
【樣例輸出0】
383726909
【樣例輸入1】
100 1
【樣例輸出1】
265470434
【樣例輸入2】
100 2
【樣例輸出2】
376611634
【樣例輸入3】
100 3
【樣例輸出3】
627595255
這題就是相當於考了一個卡特蘭數,然而我們這一批人還沒學。。。
怎麼辦呢?那就學唄
t=0,列舉向橫向移動步數,必須是偶數,則縱向步數n-i。
從中選1/2向正方向走,另一半反向走C(n,i)C(i,i/2)C((n-i),(n-i)/2)
t=1,卡特蘭數公式走起即可catalan(n)=C(2n,n)/(n+1),至於有一個奇怪的錯誤就是另一個表示式他用了會錯,不明白為什麼
t=2,使用dp,注意是四個方向
f[0]=1;
for(int i=0;i<=n;i+=2){
for(int j=0;j<=i;j+=2){
f[i]=(f[i]+f[i-j]*4%p*catlan(j/2-1)%p)%p;
}
t=3,資料累加加卡特蘭數,思路較簡單(當時重點不知道卡特蘭數是啥,汗)
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 const int p=1e9+7; 5 int hi[3000000],n,typ; 6 inline int jie(int x){ 7 if(x==1||x==0) return 1; 8 if(hi[x]) return hi[x]; 9 return hi[x]=((jie(x-1)%p)*(x%p))%p; 10 } 11 inline int fima(int a){ 12 int ans=1,b=p-2; a=a%p; 13 while(b){ 14 if(b&1) ans=(ans*a)%p; 15 b>>=1,a=(a*a)%p; 16 } return ans; 17 } 18 inline int C(int n,int m){ 19 if(n==m) return 1; 20 return jie(n)*fima(jie(m)*jie(n-m)%p)%p; 21 } 22 inline int catlan(int n){ 23 return C(2*n,n)*fima(n+1)%p; 24 } 25 inline int read(){ 26 int x=0,f=1; char ch=getchar(); 27 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 28 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 29 return x*f; 30 } 31 namespace WSN{ 32 inline int main(){ 33 n=read(),typ=read(); 34 if(typ==1) printf("%lld\n",catlan(n/2)); 35 if(typ==0){ 36 int ans=0; 37 for(int i=0;i<=n;i++) 38 if(!(i&1)) ans=(ans+C(n,i)*C(i,i/2)%p*C((n-i),(n-i)/2)%p)%p; 39 printf("%lld\n",ans); 40 } 41 if(typ==3){ 42 int ans=0; 43 for(int i=0;i<=n;i++) 44 if(!(i&1)) ans=(ans+C(n,i)*catlan(i/2)%p*catlan((n-i)/2)%p)%p; 45 printf("%lld\n",ans); 46 } 47 if(typ==2){ 48 int f[1005]={}; 49 f[0]=1; 50 for(int i=0;i<=n;i+=2){ 51 for(int j=0;j<=i;j+=2){ 52 f[i]=(f[i]+f[i-j]*4%p*catlan(j/2-1)%p)%p; 53 } 54 } 55 printf("%lld\n",f[n]); 56 } 57 return 0; 58 } 59 } 60 signed main(){return WSN::main();}View Code
馬の思
考完試挺不爽的,居然(——————),看這次考試經歷發現還是不能死幹一道題的,風險太大了
而且T4的得分率較高,雖然是黑的,但事後想一想,六維xin隊是真的好衝
保底分拿到不是問題,可到考試結束我連第四題還沒看,真是。。。。
總結下經驗,考試打暴力,板子要記牢。。。。