【赛后总结+部分题解】2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛
赛后总结:
T:今天状态一般,甚至有点疲惫。然后12点比赛开始,和队友开始看题,从最后往前面看,发现数学题公式看不懂。然后发现队友已经双开做1001和1006了,我看着1007有人A,开始做1007。看了一会发现这是一个简单签到题,构造一下就完事了。然后一遍A,结束。在他们看1008的时候,我回去看1002和1003,1002的题意没看清楚,队友说的也有点模糊,然后不知道怎么下手。开始看1003,因为A的人真的好多呜呜呜。从AC自动机一直re转为后缀自动机,然后不会。结束了。今天对队伍的贡献太少了,复杂度也没算好,一直在re。做题策略还是有点问题,不该纠结自己不会的领域。然后也有很多不会的知识需要去弥补。
P:lucky,从中间看到的第一题就是一道签到题。但由于读题不完整,在输出格式上WA了2-3次。所幸,过了。然后,就去看了钓鱼那题,将题意告诉了队友,队友有思路直接开做,我负责着错误样例。期间,我考虑到的一个点跟队友说,队友无法理解,我就想着自己打打看。AC后,才发现,队友这次想复杂了。接着的1002,1003,只能说自己的知识储备不够,大概从题目能够知道用了什么算法,但无法解决。
J:今天状态贼差,1008WA了七八次还是没A出来,结果是我想复杂了,队友一下就A了,还是太弱了,1002是线段树,但是不知道该怎么做,看来应该做一下线段树专题了。
部分题解:
1001 ^&^
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<queue> #include<set> #include<cmath> #include<string> #include<map> #include<vector> #include<ctime> #include<stack> using namespace std; #define mm(a,b) memset(a,b,sizeof(a)) typedef long long ll; const long long mod = 1e9 + 7; const int maxn = 1e6 + 10; int main() { ll a, b, c, k, cnt; int t; cin >> t; k = 1; while (t--) { c = 0, k = 1, cnt = 0; scanf("%lld%lld", &a, &b); int flag = 1; while (a || b) { if (a & 1 && b & 1) { c += k; } else if ((a & 1) + (b & 1) == 1 && flag) { flag = 0, cnt = k; } a >>= 1, b >>= 1; k <<= 1; } if (!c) c = cnt == 0 ? 1 : cnt; printf("%lld\n", c); } }
1002 array
题解来源:https://mmfunnytree.github.io/2019/08/23/begin14/#more?tdsourcetag=s_pcqq_aiomsg 原博主的代码有点点小问题,不能直接提交哦
分析
- 首先可以想到,由于一开始给的A数组是个排列,且第一种操作加的数字固定为1e7,所以,操作1可以认为在原序列中删除了A[i]A这个数字;
- 那么我们可以把A[i]这个数字标记为已经被删除,那么下次查询的时候,一方面我们可以从原序列中去查询第一个大于等于k,且未在A[1..r]出现过的数字,另一方面,我们可以在标记删除的容器里二分找到第一个不小于k的数字,两者取小便可,根据排列的性质,这两个数字一定不会冲突;
- 所以问题就变成了,维护一个set,存放被删除的数字,构造一个主席树,然后查询的时候直接找到第一个合适的数字便可。
#pragma comment(linker, "/STACK:1024000000,1024000000") #pragma GCC optimize(2) #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<queue> #include<set> #include<cmath> #include<string> #include<map> #include<vector> #include<ctime> #include<stack> using namespace std; #define mm(a,b) memset(a,b,sizeof(a)) typedef long long ll; const long long mod = 1e9+7; const int maxn = 2e5; set<int>st; int n,m,lst; int T[maxn],lson[maxn*20],rson[maxn*20],c[maxn*20],tot; int a[maxn]; void update(int &u,int p,int l,int r) { ++tot; lson[tot]=lson[u]; rson[tot]=rson[u]; c[tot]=c[u]+1; u=tot; if(l==r) return; int mid=(l+r)>>1; if(p<=mid) update(lson[u],p,l,mid); else update(rson[u],p,mid+1,r); } int tmp1; void query(int rt,int L,int R,int l,int r) { if(tmp1<n+1) return; if(L<=l&&R>=r) { if(c[rt]==0) { tmp1=l;return; } if(c[rt]==r-l+1) return; int mid=(l+r)>>1; if(c[lson[rt]]==mid-l+1) query(rson[rt],L,R,mid+1,r); else query(lson[rt],L,R,l,mid); } int mid=(l+r)>>1; if(L<=mid) query(lson[rt],L,R,l,mid); if(R>mid) query(rson[rt],L,R,mid+1,r); } int main() { int t; scanf("%d",&t); while(t--) { st.clear(); tot=1;lst=0; scanf("%d %d",&n,&m); st.insert(n+1); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); T[i]=T[i-1]; update(T[i],a[i],1,n); } int op,pos,r,k; while(m--) { scanf("%d",&op); if(op==1) { scanf("%d",&pos); pos^=lst; st.insert(a[pos]); } else { scanf("%d %d",&r,&k); r^=lst,k^=lst; int ans=*(st.lower_bound(k)); tmp1=n+1; query(T[r],k,n,1,n); ans=min(ans,tmp1); printf("%d\n",ans); lst=ans; } } } return 0; }
1003 K-th occurrence
#pragma comment(linker, "/STACK:1024000000,1024000000") #pragma GCC optimize(2) #include <bits/stdc++.h> using namespace std; #define mm(a,b) memset(a,b,sizeof(a)) typedef long long ll; const long long mod = 998244353; const int maxn = 1e5+5; const int inf = 0x3f3f3f3f; char s[maxn]; struct Tree{ int tot, rt[maxn], lson[maxn*20], rson[maxn*20], cnt[maxn*20]; int build (int l, int r) { int o = ++tot; int mid = (l + r) >> 1; cnt[o] = 0; if (l != r) { lson[o] = build(l, mid); rson[o] = build(mid+1, r); } return o; } int update(int prev, int l, int r, int v) { int o = ++tot; int mid = (l + r) >> 1; lson[o] = lson[prev]; rson[o] = rson[prev]; cnt[o] = cnt[prev] + 1; if (l != r) { if (v <= mid) lson[o] = update(lson[o], l, mid, v); else rson[o] = update(rson[o], mid+1, r, v); } return o; } int query(int u, int v, int l, int r, int k) { if (l == r) return l; int mid = (l + r) >> 1; int num = cnt[lson[v]] - cnt[lson[u]]; if (num >= k) return query(lson[u], lson[v], l, mid, k); else return query(rson[u], rson[v], mid+1, r, k-num); } }; struct SuffixArray{ // 下标1 int cntA[maxn], cntB[maxn], A[maxn], B[maxn]; int Sa[maxn], tsa[maxn], height[maxn], Rank[maxn]; // Sa[i] 排名第i的下标, Rank[i] 下标i的排名 int n, dp[maxn][18]; Tree T; void build() { T.tot = 0; T.rt[0] = T.build(1, n); for (int i = 1; i <= n; ++i) T.rt[i] = T.update(T.rt[i-1], 1, n, Sa[i]); } void init(char *buf, int len) { // 预处理,sa,rank,height n = len; for (int i = 0; i < 128; ++i) cntA[i] = 0; for (int i = 1; i <= n; ++i) cntA[(int)buf[i]]++; for (int i = 1; i < 128; ++i) cntA[i] += cntA[i-1]; for (int i = n; i >= 1; --i) Sa[ cntA[(int)buf[i]]-- ] = i; Rank[ Sa[1] ] = 1; for (int i = 2; i <= n; ++i) { Rank[Sa[i]] = Rank[Sa[i-1]]; if (buf[Sa[i]] != buf[Sa[i-1]]) Rank[Sa[i]]++; } for (int l = 1; Rank[Sa[n]] < n; l <<= 1) { for (int i = 0; i <= n; ++i) cntA[i] = 0; for (int i = 0; i <= n; ++i) cntB[i] = 0; for (int i = 1; i <= n; ++i) { cntA[ A[i] = Rank[i] ]++; cntB[ B[i] = (i + l <= n) ? Rank[i+l] : 0]++; } for (int i = 1; i <= n; ++i) cntB[i] += cntB[i-1]; for (int i = n; i >= 1; --i) tsa[ cntB[B[i]]-- ] = i; for (int i = 1; i <= n; ++i) cntA[i] += cntA[i-1]; for (int i = n; i >= 1; --i) Sa[ cntA[A[tsa[i]]]-- ] = tsa[i]; Rank[ Sa[1] ] = 1; for (int i = 2; i <= n; ++i) { Rank[Sa[i]] = Rank[Sa[i-1]]; if (A[Sa[i]] != A[Sa[i-1]] || B[Sa[i]] != B[Sa[i-1]]) Rank[Sa[i]]++; } } for (int i = 1, j = 0; i <= n; ++i) { if (j) --j; int tmp = Sa[Rank[i] - 1]; while (i + j <= n && tmp + j <= n && buf[i+j] == buf[tmp+j]) ++j; height[Rank[i]] = j; } } void st() { for (int i = 1; i <= n; ++i) { dp[i][0] = height[i]; } for (int j = 1; j <= log2(n); ++j) { for (int i = 1; i + (1 << j) - 1 <= n; ++i) { dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]); } } } int rmq(int l, int r) { if (l == r) return inf; l++; int len = r - l + 1; int x = log2(len); return min(dp[l][x], dp[r - (1 << x) + 1][x]); } int findl(int pos, int len) { int l = 1, r = pos; while (l <= r) { int mid = (l + r) >> 1; if (rmq(mid, pos) < len) l = mid + 1; else r = mid - 1; } return l; } int findr(int pos, int len) { int l = pos, r = n; while (l <= r) { int mid = (l + r) >> 1; if (rmq(pos, mid) < len) r = mid - 1; else l = mid + 1; } return r; } int solve(int ql, int qr, int k) { int len = qr - ql + 1; int pos = Rank[ql]; int l = findl(pos, len); int r = findr(pos, len); if (r - l + 1 < k) return -1; return T.query(T.rt[l-1], T.rt[r], 1, n, k); } }S; int main() { int T; scanf("%d",&T); while(T--) { int n,m; scanf("%d %d",&n,&m); scanf("%s",s+1); S.init(s,strlen(s+1)); S.st(); S.build(); int l,r,k; for(int i=0;i<m;i++) { scanf("%d %d %d",&l,&r,&k); printf("%d\n",S.solve(l,r,k)); } } return 0; }
1006 Shuffle Card
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<set> #include<string> #include<map> #include<vector> #include<ctime> #include<stack> #include<fstream> #include<iomanip> using namespace std; #define mm(a,b) memset(a,b,sizeof(a)) typedef long long ll; typedef unsigned long long ull; const int maxn = 1e5+10; const int inf = 0x3f3f3f3f; const int mod = 998244353; const double PI = acos(-1.0); int a[maxn]; int b[maxn]; map<int,int> ma; int main(){ int n,m; scanf("%d %d",&n,&m); for(int i=0;i<n;i++) scanf("%d",a+i); for(int i=0;i<m;i++) scanf("%d",b+i); for(int i=m-1;i>=0;i--){ if(ma[b[i]]) b[i]=0; else ma[b[i]]=1; } int sum=0; for(int i=m-1;i>=0;i--){ if(b[i]!=0){ printf("%d ",b[i]); sum++; } if(sum==n) break; } if(sum!=n){ for(int i=0;i<n;i++){ if(!ma[a[i]]){ printf("%d ",a[i]); sum++; } if(sum==n) break; } } return 0; }
1007 Windows of CCPC
#pragma comment(linker, "/STACK:1024000000,1024000000") #pragma GCC optimize(2) #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<queue> #include<set> #include<cmath> #include<string> #include<map> #include<vector> #include<ctime> #include<stack> using namespace std; #define mm(a,b) memset(a,b,sizeof(a)) typedef long long ll; const long long mod = 1e9+7; const int maxn = 2e5; char mp[2000][2000]; int num[20]; void init() { num[0]=1; for(int i=1;i<=10;i++) { num[i]=num[i-1]*2; } mp[1][1]='C'; mp[1][2]='C'; mp[2][1]='P'; mp[2][2]='C'; for(int i=2;i<=10;i++) { for(int j=1;j<=num[i];j++) { for(int k=1;k<=num[i];k++) { if(j<=num[i-1]&&k<=num[i-1]) continue; if(k>num[i-1]&&j<=num[i-1]) { mp[j][k]=mp[j][k-num[i-1]]; } else if(j>num[i-1]&&k>num[i-1]) { mp[j][k]=mp[j-num[i-1]][k-num[i-1]]; } else if(j>num[i-1]&&k<=num[i-1]) { if(mp[j-num[i-1]][k]=='C') mp[j][k]='P'; else mp[j][k]='C'; } } } } } int main() { init(); int T; scanf("%d",&T); while(T--) { int k; scanf("%d",&k); for(int i=1;i<=num[k];i++) { for(int j=1;j<=num[k];j++) { printf("%c",mp[i][j]); } printf("\n"); } } // return 0; }
1008Fishing Master
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<queue> #include<set> #include<cmath> #include<string> #include<map> #include<vector> #include<ctime> #include<stack> using namespace std; #define mm(a,b) memset(a,b,sizeof(a)) typedef long long ll; const long long mod = 1e9 + 7; const int maxn = 1e6 + 10; int t, n, vis[maxn]; ll a[maxn], k; struct node{ int id; ll yu; }extra[maxn]; bool cmp(node a,node b) { return a.yu>b.yu; } int main() { ll ans = 0, cnt, sum; cin >> t; while (t--) { queue<ll>q; ans = 0; cnt = 1; sum = 0; scanf("%d%lld", &n, &k); ans+=k; for (int i = 0; i < n; ++i) { scanf("%lld", &a[i]); cnt+=a[i]/k; extra[i].id=i; extra[i].yu=a[i]%k; ans+=a[i]; } if(cnt<n){ sort(extra,extra+n,cmp); for(ll i=0;i<=n-cnt-1;i++){ ans+=k-extra[i].yu; } } printf("%lld\n",ans); } }