QAQ:这场比赛打了,A掉三题,挺快乐的,希望今年比赛成绩能好一点,Hello 2020。
A. New Year and Naming
字符串取余拼接,简单题。
#include <bits/stdc++.h> using namespace std; const int maxn = 25; string s[maxn],t[maxn]; int main() { int n ,m; cin >> n >> m; for(int i = 0;i<n;i++) cin >> s[i]; for(int i = 0;i<m;++i) cin >> t[i]; int q,x; cin >> q; while(q--) { int x; cin >> x; cout << s[(x-1)%n] << t[(x-1)%m] << endl; } return 0; }
B. New Year and Ascent Sequence
分情况讨论,先把题目给出的集合划分为两种,对于本身就构成ascent的集合,我们不用处理他们,这一类集合的数目为cnt1,对于剩下的,他们本身无法形成ascent,就需要与其他集合进行拼接,因此我们记录每个集合的最大值和最小值,将两个数组数组从小到大排序,将最小值数组作为放在前面的sx,然后在最大值数组中找比这个值大的值的数目,就是以当前集合作为sx,所求的组合数。总的数目可记为cnt2。
那么最终结果就是ans = cnt1*n(本身就能够成ascent的集合放在前面的情况数)+(n-cnt1)*cnt1(本身就能够成ascent的集合放在后面的情况数去除重复后的数目)+cnt2。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5+10; int num[maxn]; int A[maxn],B[maxn]; typedef long long LL; int main() { LL cnt = 0; int n,len = 0; scanf("%d",&n); for(int k = 0;k<n;k++) { int l; scanf("%d",&l); for(int i = 0;i<l;i++) { scanf("%d",&num[i]); } int ma,mi; ma =mi = num[0]; bool flag = false; num[l] = num[l-1]; for(int i = 0;i<l;++i) { ma = max(num[i],ma); mi = min(num[i],mi); if(num[i]<num[i+1]) { //if(!flag) flag = true; } } if(flag) cnt++; else { A[len] = mi; B[len++] = ma; } // cout << len << endl; } sort(A,A+len); sort(B,B+len); LL sum = 0; for(int i = 0;i<len;++i) { int d = upper_bound(B,B+len,A[i]) - B; //cout << A[i] << " " << d << endl; sum +=(len-d); } //cout << cnt << " " << sum << endl; cout << cnt*(LL)n+((LL)n-cnt)*cnt+sum << endl; return 0; }
C. New Year and Permutation
数学题,考虑选择长度为k的子区间,选法共有(n-k+1)种,这个集合的排列方式共有k!,选出来的这个集合与剩下的数字的排列组合方式共有(n-k+1)种,那么答案就是(n-k+1)*k!*(n-k+1)!,k从1-n。
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 250000+50; LL num[maxn]; void getf(LL n,LL m) { num[0] = 1; for(int i = 1;i<=n;i++) { num[i] = (i*(num[i-1]))%m; } return ; } int main() { LL n,m; cin >> n >> m; getf(n,m); LL ans = 0; LL sum; for(int i = 1;i<=n;i++) { sum = (n+1-i)*(n+1-i); sum%=m; sum = (sum*num[i])%m; sum = (sum*(num[n-i]))%m; ans = (ans+sum)%m; //cout << ans << endl; } cout << ans << endl; return 0; }
D. New Year and Conference
这个题是用线段树来解决的,我们可以把分两种情况讨论,检测在a场所冲突的在b场所是否冲突以及检测在b场所冲突的在a场所是否冲突,我们可以将sa作为排序第一关键词,ea作为排序第二关键词,排序以后,先考虑第一种情况,我们枚举第i个表演,二分查找与他在a场所冲突的节目的区间,然后利用线段树求解区间的Smax,和Emin,要是存在不冲突的情况的话,就是Smax>p[i].eb||Emin<p[i].sb,存在返回0,如果在a场所冲突的在b场所也都冲突的话,继续进行第二种情况的判断,我们可以发现,事实上,情况1和2处理方法完全一致,因此我们可以交换每个表演在a,b场所的区间,然后再来一遍,就能得到最终结果
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> P; const int maxn = 1e5+100; struct node { int sa,ea,sb,eb; node(){} node(int a,int b,int c,int d):sa(a),ea(b),sb(c),eb(d){} bool operator <(node b)const { if(sa==b.sa) return ea<b.ea; return sa<b.sa; } }p[maxn]; int mx[4*maxn],mi[4*maxn]; void creat(int l,int r,int k) { if(l==r) { mx[k] = p[l].sb,mi[k] =p[l].eb; return ; } int mid = (l+r)/2; creat(l,mid,2*k); creat(mid+1,r,2*k+1); mx[k] = max(mx[2*k],mx[2*k+1]); mi[k] = min(mi[2*k],mi[2*k+1]); } int querymin(int l,int r,int al,int ar,int k) { if(l==al&&r==ar) return mi[k]; int mid=(l+r)/2; if(ar<=mid) return querymin(l,mid,al,ar,2*k); else if(al>mid) return querymin(mid+1,r,al,ar,2*k+1); else return min(querymin(l,mid,al,mid,2*k),querymin(mid+1,r,mid+1,ar,2*k+1)); } int querymax(int l,int r,int al,int ar,int k) { if(l==al&&r==ar) return mx[k]; int mid = (l+r)/2; if(ar<=mid) return querymax(l,mid,al,ar,2*k); else if(al>mid) return querymax(mid+1,r,al,ar,2*k+1); else return max(querymax(l,mid,al,mid,2*k),querymax(mid+1,r,mid+1,ar,2*k+1)); } bool solve(int n) { sort(p+1,p+1+n); creat(1,n,1); for(int i = 1;i<=n;++i) { int pos = lower_bound(p+1,p+1+n,node(p[i].ea,1e9+1000,0,0))-p-1; if(!(i+1<=pos)) continue; if(querymin(1,n,i+1,pos,1)<p[i].sb||querymax(1,n,i+1,pos,1)>p[i].eb) return false; } return true; } int main() { int n,i,j,l,sig = 1; scanf("%d",&n); for(i = 1;i<=n;++i) { scanf("%d%d%d%d",&p[i].sa,&p[i].ea,&p[i].sb,&p[i].eb); } sig&=solve(n); for(i = 1;i<=n;++i) swap(p[i].sa,p[i].sb),swap(p[i].ea,p[i].eb); sig&=solve(n); if(sig) printf("YES "); else printf("NO "); return 0; }
未完待续……