2020hdu多校第七场比赛及补题
1009 Increasing 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; }
1010 Jogging
一个无限大的二维地图,一个格子坐标为(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; }
1004 Decision
难的一匹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; }