2020hdu多校第七場比賽及補題
1009Increasing and Decreasing
一個n的全排列,它的最長上升子序列長度為x,它的最長下降子序列長度為y,讓你構造一個這樣的字典序最小的全排列
這簽到題好難,我也只是猜出來的結論,也不怎麼清楚怎麼證明,我的思路就是分為 x 個下降子序列,比如x=3,y=5時,若n = 15我構造出來的是 5 4 3 2 1 10 9 8 7 6 15 14 13 12 11,若n = 14,我構造出來的是 4 3 2 1 10 9 8 7 6 15 14 13 12 11,就是這種構造法
#include<iostream> #include<algorithm> using namespace std; const int MAXN = 1e5+7; int ans[MAXN]; int lolo[MAXN]; int main() { int T, n, x, y; cin >> T; while(T--){ cin >> n >> x >> y; if(x+y>n+1){ cout<<"NO"<<endl; continue; } for (int i = 1;i <= n;i++) ans[i] = 0; bool flag = false; int cnt = 0; int lis = 0; int cs = n/y; if(y * cs < n) cs++; if(x < cs){ cout<<"NO"<<endl; continue; } int su = n - x; for(int i = 1;i <= x;i++){ lolo[i] = 1; } for(int i = x;i;i--){ if(su >= y - 1){ su -= y - 1; lolo[i] += y - 1; } else if(su){ lolo[i] += su; su = 0; } else break; } int pos = 0; for(int i = 1;i <= x;i++){ for(int j = 1;j <= lolo[i];j++){ pos++; ans[pos] = cnt + lolo[i] - j + 1; } cnt += lolo[i]; //cout<<lolo[i]<<endl; } cout<<"YES"<<endl; for(int i = 1;i < n;i++){ printf("%d ",ans[i]); } printf("%d\n",ans[n]); } return 0; }
1010Jogging
一個無限大的二維地圖,一個格子座標為(x,y),若x,y互質,那這個格子就是牆,否則這個格子就是一個空地
現給一個初始座標,每次跳遠可以等概率的跳到周圍八格的空地和自身的格子裡(周圍八格有z格空地,那跳到這z格的概率分別為1/(z+1),跳到自己身上的一格的概率也是1/(z+1) )
問跳躍無數次後,回到初始座標的概率
分析:
- 首先,座標互質的格子為牆,其餘為空地,和一個叫恐怖稽器人的題一樣,有著一些性質:
- 1、對角線上的格子,除了(1,1),全是空地,所以如果可以跳到對角線,那麼就可以跳到對角線上所有的格子(無限)
- 2、如果不能跳到對角線,那麼可以跳到的格子是很有限的
- 上面的兩個性質可以把一部分地圖輸出出來,觀察得到,那麼如果能跳到對角線,回到初始座標的概率就為0,如果周圍八格都是牆,概率為1,else,概率為0到1之間的分數
計算:
概率為(0,1]時,該怎麼計算這個概率,我做的時候感覺自己算不來,因為我概率題沒學過,就先看其他題了,沒多想這個,雖然沒多想,但我還是觀察到一個東西的,在一個樣例中:
1號格子能跳到1號,2號
2號格子能跳到1號,2號,3號
3號格子能跳到2號,3號
初始座標在1號格子
樣例的答案時2 / 7
1號格子能跳到2個格子
2號格子能跳到3個格子
3號格子能跳到2個格子
2 / 2 + 3 + 2恰好等於 2 / 7
當時我感覺應該不是這麼簡單的,後來突然想要判斷這個計算方法是否正確
然後我還真的證出就是這樣算的
#include<iostream> #include<algorithm> using namespace std; bool vis[400][400]; long long res[400][400]; long long opx[8] = {-1,-1,-1,0,0,1,1,1}; long long opy[8] = {-1,0,1,-1,1,-1,0,1}; long long gcd(long long a,long long b){ if(a<b) swap(a,b); while(b){ a = a % b; swap(a,b); } return a; } int fz,fm; long long sx, sy; bool flag; void dfs(long long xx,long long yy){ vis[200+xx][200+yy] = true; res[200+xx][200+yy] = 1; for(int i = 0;i < 8;i++ ){ long long dx = xx + opx[i], dy = yy + opy[i]; if(gcd(sx + dx,sy + dy) > 1){ res[200+xx][200+yy]++; if(vis[200+dx][200+dy]) continue; if(sx + dx == sy + dy){ flag = false; return; } dfs(dx,dy); if(sx + dx == sy + dy){ flag = false; return; } } } //cout<<res[200+xx][200+yy]<<endl; fm += res[200+xx][200+yy]; } int main() { int T; cin >> T; while(T--){ cin>>sx>>sy; fz = fm = 0; for(int i = 0;i < 400;i++){ for(int j = 0;j < 400;j++){ vis[i][j] = false; res[i][j] = 0; } } flag = true; dfs(0,0); if(!flag) { cout<<"0/1"<<endl; continue; } fz = res[200][200]; long long g = gcd(fz,fm); fz /= g;fm /= g; cout<<fz<<"/"<<fm<<endl; } return 0; }
1004Decision
難的一匹OAO,補題補了好久
題意:給定t,a,c,m。2t<=m
u,v是在[0,t]範圍內的隨機的數(取各個數字的概率相同),X[0] = u + v, X[i] = (X[i-1] * a + c) % m (i >= 1),如果X[ | u-v| ] 為偶數則獲勝,問獲勝的概率
看到這個,我是想到會成一個環,然後自己就開始寫了,寫了好長,然後樣例都過不了,才發現這不是一個環
看了題解才知道這是一個環套樹森林,我自己寫的程式碼又長又爛又錯的離譜,看了下std,很短很簡潔orz, 果然acmer與acmer的體質是不能一概而論的
正解是倍增,這種思路我很少用到,寫的時候把人寫傻了
#include<iostream> #include<algorithm> using namespace std; const int MAXN = 1e6+7; int fa[20][MAXN]; long long dp[20][MAXN]; long long fz,fm; void cnt(int p,int k){ for(int i = 19;i >= 0;i--){ if((1<<i)>k) continue; fz += dp[i][p] * 2; k -= 1<<i; p = fa[i+1][p]; } } long long gcd(long long a,long long b){ if(a<b) swap(a,b); while(b){ a = a % b; swap(a,b); } return a; } int main() { int T; cin>>T; long long t,a,c,m; while(T--){ cin>>t>>a>>c>>m; fz = 0; for(long long i = 0;i < m; i++) { fa[0][i] = (i * a + c) % m; dp[0][i] = (fa[0][i] % 2 == 0); } for(int i = 1;i < 20; i++){ for(int j = 0;j < m;j++){ fa[i][j] = fa[i-1][fa[i-1][j]]; dp[i][j] = dp[i-1][j] + dp[i-1][fa[i][j]]; } } for(int i = 0;i <= t;i++){ if(i%2) cnt(i,i/2+1); else { fz++; cnt(fa[0][i],i/2); } } for(int i = t + 1;i <= 2 * t;i++){ if(i%2) cnt(i,(2 * t - i) / 2 + 1); else { fz++; cnt(fa[0][i],(2 * t - i) / 2); } } fm = (t+1)*(t+1); long long gg = gcd(fz,fm); fz/=gg;fm/=gg; cout<<fz<<"/"<<fm<<endl; } return 0; }