2018 Multi-University Training Contest 8
Posted shutdown113
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018 Multi-University Training Contest 8相关的知识,希望对你有一定的参考价值。
Character Encoding
题意:
随机挑出m个数字,满足每个数字位于【0,n-1】区间内且所有数相加等于k,问一共有多少种选法?
分析:
不难看出该题目可以变换成将k个1分成m块的个数,即在k个1中插m-1个板子,根据隔板法,放的方法数有C(k+m-1,m-1)。考虑分块后有的块所有数字相加和超过n-1,需要去掉这种特殊情况。假设一共有i块>=n,那么x1+x2+x3……+xm=k,等式两边同时减去i*n,这样等式就变成了x1‘+x2‘+……+xm‘=k-i*n。因为违反规定的i块都减去了n,所以违反规定的块的范围就从>=n,变成了>=0,而x1‘+x2‘+……+xm‘=k-i*n式子的含义将k-i*n个1分成m块的个数,为C(k-i*n+m-1,m-1),最后用容斥原理去掉重复计算的情况就好了。
参考博客:大佬博客
代码:
#include <queue> #include <vector> #include <math.h> #include <string> #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define ull unsigned long long #define cls(x) memset(x,0,sizeof(x)) #define clslow(x) memset(x,-1,sizeof(x)) const int maxn=2e5+100; const int mod=998244353; int n,m,k,T; ll fac[maxn],inv[maxn]; ll poww(ll a,int k) { ll res=1; while(k) { if(k&1) res=res*a%mod; a=a*a%mod; k>>=1; } return res; } void getinv() { fac[0]=fac[1]=1; for(int i=2;i<maxn;i++){ fac[i]=fac[i-1]*i%mod; } inv[maxn-1]=poww(fac[maxn-1],mod-2); for(int i=maxn-2;i>=0;i--){ inv[i]=inv[i+1]*(i+1)%mod; } } ll C(int n,int m) { if(m>n) return 0; return fac[n]*inv[n-m]%mod*inv[m]%mod; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif // ONLINE_JUDGE getinv(); scanf("%d",&T); while(T--) { scanf("%d %d %d",&n,&m,&k); ll ans=0; int sign=-1; for(int i=0;i<=k/n;i++){ sign=-sign; ans=(ans+sign*C(m,i)*C(m-1+k-i*n,m-1)%mod+mod)%mod; } printf("%lld ",ans); } return 0; }
Parentheses Matrix
题意:
如果空串为平衡串;如果A是平衡的,name(A)也是平衡的;如果A,B是平衡的,那么AB是平衡的。定义矩阵的godness值,为矩阵的平衡的行和列的个数。给出矩阵的行列,要求构造godness值最大的矩阵。
分析:
如果矩阵的行列值都为奇数,那么godness一定为0,随意输出就好。
如果矩阵的行列值一个为奇数,一个为偶数,那么就让为偶数的平衡就好了。
如果矩阵的行列值都为偶数,考虑两种构造方法,一种是先让行(列)先满足,然后再尽量去匹配列(行),godness值为max(n+m/2-1,m+n/2-1)。另一种是让行列匹配相加和尽可能多,godness值为n+m-4。
代码:
#include <queue> #include <vector> #include <math.h> #include <string> #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define ull unsigned long long #define cls(x) memset(x,0,sizeof(x)) #define clslow(x) memset(x,-1,sizeof(x)) const int maxn=500; char graph[maxn][maxn]; int n,m,T; void solve_n() { for(int i=1;i<=n;i++){ if(i<=n/2){ graph[i][1]=‘(‘; graph[i][m]=‘)‘; for(int j=2;j<m;j++){ if(j%2==0) graph[i][j]=‘(‘; else graph[i][j]=‘)‘; } } else { for(int j=1;j<=m;j++){ if(j%2==1) graph[i][j]=‘(‘; else graph[i][j]=‘)‘; } } } } void solve_m() { for(int j=1;j<=m;j++){ for(int i=1;i<=n;i++){ if(j<=m/2){ if(i%2==0) graph[i][j]=‘(‘; else graph[i][j]=‘)‘; if(i==1) graph[1][j]=‘(‘; else if(i==n) graph[n][j]=‘)‘; } else{ if(i%2==1) graph[i][j]=‘(‘; else graph[i][j]=‘)‘; } } } } void solve() { for(int j=1;j<=m;j++) graph[1][j]=‘(‘,graph[n][j]=‘)‘; for(int i=2;i<n;i++){ if(i%2==0){ for(int j=1;j<=m;j++){ if(j%2==1) graph[i][j]=‘(‘; else graph[i][j]=‘)‘; } } else { graph[i][1]=‘(‘; graph[i][m]=‘)‘; for(int j=2;j<m;j++){ if(j%2==0) graph[i][j]=‘(‘; else graph[i][j]=‘)‘; } } } } void print() { for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ printf("%c",graph[i][j]); } printf(" "); } } int main() { // freopen("in.txt","r",stdin); scanf("%d",&T); while(T--) { scanf("%d %d",&n,&m); if(n%2==0&&m%2==0){ if(n>2&&m>2&&n+m-4>max(n+m/2-1,m+n/2-1)){ solve(); } else { if(n>m) solve_n(); else solve_m(); } } else if(n%2==0) solve_m(); else if(m%2==0) solve_n(); else solve_n(); print(); } return 0; }
Magic Square
题目:
给出两种操作,顺时针旋转(逆时针旋转)一个矩阵,最后输出总矩阵。
分析:
直接模拟就好。
代码:
include <queue> #include <vector> #include <math.h> #include <string> #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define ull unsigned long long #define cls(x) memset(x,0,sizeof(x)) #define clslow(x) memset(x,-1,sizeof(x)) const int maxn=1e5+100; int g[10][10]; void spin_c(int x) { int r=(x>2?2:1); int c=(x%2==1?1:2); int tmp=g[r][c]; g[r][c]=g[r+1][c]; g[r+1][c]=g[r+1][c+1]; g[r+1][c+1]=g[r][c+1]; g[r][c+1]=tmp; } void spin_r(int x) { int r=(x>2?2:1); int c=(x%2==1?1:2); int tmp=g[r][c]; g[r][c]=g[r][c+1]; g[r][c+1]=g[r+1][c+1]; g[r+1][c+1]=g[r+1][c]; g[r+1][c]=tmp; } int main() { // freopen("in.txt","r",stdin); int n,T; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=3;i++){ for(int j=1;j<=3;j++){ scanf("%1d",&g[i][j]); } } for(int i=1;i<=n;i++){ int id; char ch; scanf("%d%c",&id,&ch); if(ch==‘C‘) spin_c(id); else if(ch==‘R‘) spin_r(id); } for(int i=1;i<=3;i++){ for(int j=1;j<=3;j++){ printf("%d",g[i][j]); } printf(" "); } } return 0; }
Taotao Picks Apples
题意:
给出两种操作,修改序列的第x个值为y,询问这个序列的最长上升子序列的长度。
分析:
代码:
线段树
#include <map> #include <queue> #include <math.h> #include <string> #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define ull unsigned long long #define cls(x) memset(x,0,sizeof(x)) #define clslow(x) memset(x,-1,sizeof(x)) const int maxn=1e5+100; int n,q,T; int arr[maxn]; namespace IntervalTree { #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int cnt[maxn<<2],maxx[maxn<<2]; int query(int v,int l,int r,int rt) { if(l==r) return maxx[rt]>v; if(maxx[rt]<=v) return 0; int m=(l+r)>>1; if(maxx[rt<<1]<=v) return query(v,rson); else return cnt[rt]-cnt[rt<<1]+query(v,lson); } void PushUp(int l,int r,int rt) { int m=(l+r)>>1; maxx[rt]=max(maxx[rt<<1],maxx[rt<<1|1]); cnt[rt]=cnt[rt<<1]+query(maxx[rt<<1],rson); } void build(int l,int r,int rt) { if(l==r){ cnt[rt]=1; maxx[rt]=arr[l]; return; } int m=(l+r)>>1; build(lson); build(rson); PushUp(l,r,rt); } void update(int p,int c,int l,int r,int rt) { if(l==r){ cnt[rt]=1; maxx[rt]=c; return; } int m=(l+r)>>1; if(p<=m) update(p,c,lson); else update(p,c,rson); PushUp(l,r,rt); } } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif // ONLINE_JUDGE scanf("%d",&T); while(T--) { scanf("%d %d",&n,&q); for(int i=1;i<=n;i++){ scanf("%d",&arr[i]); } IntervalTree::build(1,n,1); for(int i=1;i<=q;i++){ int x,y; scanf("%d %d",&x,&y); int pre=arr[x]; IntervalTree::update(x,y,1,n,1); printf("%d ",IntervalTree::query(-1,1,n,1)); IntervalTree::update(x,pre,1,n,1); } } return 0; }
ST+dp
#include <map> #include <queue> #include <math.h> #include <string> #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define ull unsigned long long #define cls(x) memset(x,0,sizeof(x)) #define clslow(x) memset(x,-1,sizeof(x)) const int maxn=1e5+100; int n,q,T; int arr[maxn],dp[2][maxn]; namespace ST { const int maxlog=30; int d[maxn][maxlog]; void init(int n) { for(int i=1;i<=n;i++) d[i][0]=i; for(int j=1;(1<<j)<=n;j++){ for(int i=1;i+(1<<j)-1<=n;i++){ int L=d[i][j-1],R=d[i+(1<<(j-1))][j-1]; if(arr[L]>=arr[R]) d[i][j]=L; else d[i][j]=R; } } } int query(int L,int R) { if(R<L) return 0; int k=0; while((1<<(k+1))<=R-L+1) k++; int l=d[L][k],r=d[R-(1<<k)+1][k]; if(arr[l]>=arr[r]) return l; return r; } }; int binary_Search(int p,int key) { int l=p+1,r=n; if(arr[ST::query(l,r)]<=key||l>r) return 0; while(l<r) { int mid=l+(r-l)/2; if(arr[ST::query(l,mid)]>key) r=mid; else l=mid+1; } return r; } void initdp() { int pos=1; dp[0][1]=1; for(int i=2;i<=n;i++){ if(arr[i]>arr[pos]){ dp[0][i]=dp[0][pos]+1; pos=i; } else dp[0][i]=-1; } dp[1][n]=1; for(int i=n-1;i>=1;i--){ int p=binary_Search(i,arr[i]); if(p&&arr[p]>arr[i]) dp[1][i]=dp[1][p]+1; else dp[1][i]=1; } } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif // ONLINE_JUDGE scanf("%d",&T); while(T--) { scanf("%d %d",&n,&q); for(int i=1;i<=n;i++){ scanf("%d",&arr[i]); } ST::init(n); initdp(); for(int i=1;i<=q;i++){ int x,y,ans=0; scanf("%d %d",&x,&y); int p=ST::query(1,x-1),mx=arr[p]; ans+=dp[0][p]; if(y>arr[p]){ ans++; mx=y; } p=binary_Search(x,mx); if(p&&arr[p]>mx) ans+=dp[1][p]; printf("%d ",ans); } } return 0; }
以上是关于2018 Multi-University Training Contest 8的主要内容,如果未能解决你的问题,请参考以下文章
2018 Multi-University Training Contest 2
2018 Multi-University Training Contest 9
2018 Multi-University Training Contest 4
2018 Multi-University Training Contest 4