2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛
参考我的博客杜教筛
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1000010; const ll mod=1e9+7; int prime[maxn],f[maxn],sum[maxn],cnt; bool vis[maxn]; int pow_mod(int a,int b) { int res = 1; while (b) { if (b & 1) res = 1ll*res * a % mod; b >>= 1; a = 1ll*a * a % mod; } return res; } void init() { int N = maxn - 1; f[1] = 1; sum[1] = 1; for (int i = 2; i <= N; i++) { if (!vis[i]) { prime[cnt++] = i; f[i] = i - 1; } for (int j = 0; j < cnt && 1ll*prime[j] * i <= N; j++) { vis[prime[j] * i] = 1; if (i % prime[j] == 0) { f[i * prime[j]] = 1ll*f[i] * prime[j]%mod; break; } f[i * prime[j]] = 1ll*f[i] * f[prime[j]]%mod; } sum[i]=(sum[i-1]+1ll*f[i]*i%mod)%mod; } } unordered_map<int,int>ma; int inv6=pow_mod(6,mod-2); int Go(int n) { if (n < maxn) return sum[n]%mod; if (ma[n]!=0) return ma[n]; int ans = 1ll * (n + 1) * n % mod * (2 * n + 1) % mod * inv6 % mod; for (int i = 2; i <= n; ){ int j = n / (n / i); ans = (ans + mod - (1ll * (j + 1) * j / 2 - 1ll * i * (i - 1) / 2) % mod * Go(n / i) % mod) % mod; i = j + 1; } return ma[n] = ans; } int main() { init(); int _; scanf("%d", &_); int inv2 = pow_mod(2, mod - 2); while (_--) { int n,a,b; scanf("%d%d%d", &n, &a, &b); printf("%d\n", (Go(n) - 1 + mod) % mod * inv2 % mod); } }
#include <bits/stdc++.h> using namespace std; typedef long long ll; int T; int n; ll k; const int maxn=1e5+5; priority_queue<ll,vector<ll>,less<ll> >q; ll c[maxn]; int main() { cin>>T; while(T--) { scanf("%d%lld",&n,&k); while(!q.empty())q.pop(); ll sum=0; for(register int i=1;i<=n;++i){ scanf("%lld",c+i); q.push(c[i]); sum+=c[i]; } sort(c+1,c+1+n); ll tot=0; for(register int i=2;i<=n;++i){ tot+=c[i]/k; } if(tot>=n-1){ printf("%lld\n",sum+k); continue; } sum+=n*k; for(register int i=1;i<n;++i){ ll cur=q.top(); q.pop(); if(cur>k){ sum-=k; cur-=k; } else{ sum-=cur; cur=0; } q.push(cur); } printf("%lld\n",sum); } return 0; }
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1e6+10; char s[12][10000][10000]; void dfs(int id,int cur){ if(id>10)return; for(register int i=1;i<=cur;++i){ for(register int j=1;j<=cur;++j){ s[id][i][j]=s[id-1][i][j]; } } for(register int i=1;i<=cur;++i){ for(register int j=cur+1;j<=2*cur;++j){ s[id][i][j]=s[id-1][i][j-cur]; } } for(register int i=cur+1;i<=2*cur;++i){ for(register int j=1;j<=cur;++j){ if(s[id-1][i-cur][j]=='C')s[id][i][j]='P'; else s[id][i][j]='C'; } } for(register int i=cur+1;i<=2*cur;++i){ for(register int j=cur+1;j<=2*cur;++j){ s[id][i][j]=s[id-1][i-cur][j-cur]; } } dfs(id+1,cur*2); } int T,n; int fast_pow(int a,int b){ int res=1; while(b){ if(b&1)res=res*a; a=a*a; b>>=1; } return res; } int main() { s[1][1][1]='C'; s[1][1][2]='C'; s[1][2][1]='P'; s[1][2][2]='C'; dfs(2,2); scanf("%d",&T); while(T--){ scanf("%d",&n); int cur=n; n=fast_pow(2,n); //cout<<"***"<<endl; for(register int i=1;i<=n;++i){ for(register int j=1;j<=n;++j){ printf("%c",s[cur][i][j]); } printf("\n"); } } return 0; }
首先询问许多子串的这种问题应该联想到后缀数组,然后我们发现对于后缀数组中的排序(sa[i]表示下标为i的后缀的排名,rk[i]表示排名为i的后缀的下标),每个后缀串与子串的最长公共前缀为该子串的串是连续的,所以我们只要求出这段连续排名的区间(因为在这里的对于子串的最长公共前缀具有单调性,用st表预处理出每个区间的最长公共前缀长度,用二分check即可),然后在这段区间上询问第k大sa[i]的数即可。
我们考虑,一个子串必定是某个后缀的前缀。
排序相邻的后缀他们的前缀一定最相似。
所以全部的一种子串必定是一些排序相邻的后缀的公共前缀。
从l开始的子串,则从rank[l]开始看,两侧height保证大于子串长度,能延伸多长,则证明有多少个这种子串。
我们用ST表维护出height的最小值,然后通过最小值二分即可,边界有些棘手。
然后我们就得到了一个height不小于子串长度的连续区间,这个区间是以原后缀的字典序排序的。
而同时,sa数组下标为排序,值为原串位置。
所以我们对这个区间在sa数组上做主席树,求第k大,即为第k个子串出现的位置。
#include <bits/stdc++.h> using namespace std; const int maxn=110010; int t1[maxn],t2[maxn],c[maxn]; bool cmp(int *r,int a,int b,int l) { return r[a] == r[b] && r[a + l] == r[b + l]; } void da(char str[],int sa[],int rank[],int height[],int n,int m) { int i, j, p, *x = t1, *y = t2; for (i = 0; i <= m; i++) c[i] = 0; for (i = 1; i <= n; i++) c[x[i] = str[i]]++; for (i = 2; i <= m; i++) c[i] += c[i - 1]; for (i = n; i >= 1; i--) sa[c[x[i]]--] = i; for (j = 1; j <= n; j <<= 1) { p = 0; for (i = n - j + 1; i <= n; i++) y[++p] = i; for (i = 1; i <= n; i++) if (sa[i] > j) y[++p] = sa[i] - j; for (i = 1; i <= m; i++) c[i] = 0; for (i = 1; i <= n; i++) c[x[y[i]]]++; for (i = 2; i <= m; i++) c[i] += c[i - 1]; for (i = n; i >= 1; i--) { sa[c[x[y[i]]]--] = y[i]; y[i] = 0; } swap(x, y); p = 1; x[sa[1]] = 1; for (i = 2; i <= n; i++) x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p : ++p; if (p == n) break; m = p; } int k = 0; for (i = 1; i <= n; i++) rank[sa[i]] = i; for (i = 1; i <= n; i++) { if (rank[i] == 1) continue; if (k) k--; j = sa[rank[i] - 1]; while (j + k <= n && str[i + k] == str[j + k]) k++; height[rank[i]] = k; } } char str[maxn]; int sa[maxn],rk[maxn],height[maxn],n,q,st[maxn][20]; void build_st() { for (int i = 1; i <= n; i++) st[i][0] = height[i]; for (int k = 1; k <= 19; k++) { for (int i = 1; i + (1 << k) - 1 <= n; i++) { st[i][k] = min(st[i][k - 1], st[i + (1 << k - 1)][k - 1]); } } } int lcp(int a,int b){ a=rk[a]; b=rk[b]; if (a>b) swap(a,b); if (a==b) return n-sa[a]; int t=log2(b-a); return min(st[a+1][t],st[b-(1<<t)+1][t]); } struct node { int l,r,sum; } hjt[maxn*40]; int cnt,root[maxn*40]; void insert(int l,int r,int pre,int &now,int p) { hjt[++cnt]=hjt[pre]; now=cnt; hjt[now].sum++; if (l==r) { return; } int mid=(l+r)>>1; if (p<=mid) { insert(l,mid,hjt[pre].l,hjt[now].l,p); } else { insert(mid+1,r,hjt[pre].r,hjt[now].r,p); } } int query(int l,int r,int L,int R,int k) { if (l==r) return l; int mid=(l+r)>>1; int tmp=hjt[hjt[R].l].sum-hjt[hjt[L].l].sum; if (k<=tmp) { return query(l,mid,hjt[L].l,hjt[R].l,k); } else { return query(mid+1,r,hjt[L].r,hjt[R].r,k-tmp); } } vector<int>v; void init(){ cnt=0; v.clear(); for (int i=0;i<=n;i++) { root[i]=hjt[i].l=hjt[i].r=hjt[i].sum=0; } } int getid(int x) { return lower_bound(v.begin(),v.end(),x)-v.begin()+1; } int main() { int _; scanf("%d", &_); while (_--) { scanf("%d%d", &n, &q); scanf("%s", str + 1); da(str, sa, rk, height, n, 128); build_st(); init(); for (int i = 1; i <= n; i++) { v.push_back(sa[i]); } sort(v.begin(),v.end()); for (int i=1;i<=n;i++){ insert(1, n, root[i - 1], root[i], getid(sa[i])); } while (q--) { int l, r, k; scanf("%d%d%d", &l, &r, &k); int ll, rr, len = r - l + 1; int left = 1, right = rk[l]; int ans = rk[l]; while (left <= right) { int mid = (left + right) >> 1; if (lcp(sa[mid], l) >= len) { right = mid - 1; ans = mid; } else { left = mid + 1; } } ll = ans; ans = rk[l]; left = rk[l]; right = n; while (left <= right) { int mid = (left + right) >> 1; if (lcp(sa[mid], l) >= len) { left = mid + 1; ans = mid; } else { right = mid - 1; } } rr=ans; if (rr-ll+1<k) printf("-1\n");else{ printf("%d\n",v[query(1,n,root[ll-1],root[rr],k)-1]); } } } }
不难看出对于每次2操作,答案最大是n+1(因为每次更新是+10000000, 永远不会占用n+1,而且k是保证<=n的). 如果某个数字被进行过1操作, 那么就代表这个数字可以用于2类操作的查询,把这个数字加到set里.对于找2类询问的答案,第一种是从a[r+1,n]里找>=k的最小值(主席树实现),第二种是从这个set里找>=k的最小值(对set进行二分查找),取两者间最小值即可.
#include <bits/stdc++.h> using namespace std; const int maxn=200100; struct node { int l,r,sum; } hjt[maxn*40]; int cnt,root[maxn*20],n,m,book[maxn]; int a[maxn]; set<int>s; set<int>::iterator it; void init() { for (int i = 0; i <= n; i++) book[i] = 0; s.clear(); root[0] = 0; cnt = 0; for (int i = 0; i < maxn * 20; i++) hjt[i].l = hjt[i].r = hjt[i].sum = 0; } void insert(int l,int r,int pre,int &now,int p) { hjt[++cnt]=hjt[pre]; now=cnt; hjt[now].sum++; if (l==r) { return; } int mid=(l+r)>>1; if (p<=mid) { insert(l,mid,hjt[pre].l,hjt[now].l,p); } else { insert(mid+1,r,hjt[pre].r,hjt[now].r,p); } } int query(int rt,int l,int r,int L,int R) { if (R < L) return -1; if (!rt) return -1; if (!hjt[rt].sum) return -1; if (l >= L && r <= R) { if (l == r) return l; else { int mid = (l + r) >> 1; int res = -1; if (L <= mid) res = query(hjt[rt].l, l, mid, L, R); if (R > mid && res == -1) res = query(hjt[rt].r, mid + 1, r, L, R); return res; } } int mid = (l + r) >> 1; int res = -1; if (L <= mid) res = query(hjt[rt].l, l, mid, L, R); if (R > mid && res == -1) res = query(hjt[rt].r, mid + 1, r, L, R); return res; } int main() { int _; scanf("%d", &_); while (_--) { scanf("%d%d", &n, &m); init(); root[n + 1] = 0; for (int i = 1; i <= n; i++) scanf("%d", &a[i]); for (int i = n; i >= 1; i--) insert(1, n, root[i + 1], root[i], a[i]); int lastans = 0; for (int i = 1; i <= m; i++) { int id; scanf("%d", &id); if (id == 1) { int t; scanf("%d", &t); int pos = t ^lastans; if (book[pos]) continue; book[pos] = 1; s.insert(a[pos]); } else { int t1, t2; scanf("%d%d", &t1, &t2); int R = (t1 ^lastans) + 1; int k = t2 ^lastans; int ans = n + 1; it = s.lower_bound(k); if (it != s.end()) ans = *it; if (R <= n) { t1 = query(root[R], 1, n, k, n); if (t1 != -1) ans = min(ans, t1); } printf("%d\n", ans); lastans = ans; } } } return 0; }
#include <bits/stdc++.h> using namespace std; typedef long long ll; ll a,b; int main() { int T; cin>>T; while(T--) { cin>>a>>b; ll ans=(a&b); if(ans==0){ ans=1; } printf("%lld\n",ans); } return 0
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=5e4+10; ll n,m,q,Q[maxn],ans[maxn],kk; typedef pair<ll,int> PII; vector<PII>G[maxn]; multiset<PII>s; multiset<PII>::iterator it,it1; int main() { int _; scanf("%d", &_); while (_--) { s.clear(); kk=0; scanf("%lld%lld%lld", &n, &m, &q); for (int i = 1; i <= n; i++) G[i].clear(); for (int i = 1, u, v, w; i <= m; i++) { scanf("%d%d%d",&u,&v,&w); G[u].push_back(make_pair(w, v)); s.insert(make_pair(w, v)); } for (int i = 1; i <= n; i++) { sort(G[i].begin(), G[i].end()); } for (int i = 1; i <= q; i++) { scanf("%lld", &Q[i]); kk = max(kk, Q[i]); } for (int i = 1; i <= kk; i++) { it = s.begin(); it1 = s.end(); it1--; ans[i] = it->first; int sz1 = s.size(); int sz = G[it->second].size(); for (int j = 0; j < sz; j++) { if (s.size() >= kk-i+1 && it->first + G[it->second][j].first >= it1->first) break; s.insert(make_pair(it->first + G[it->second][j].first, G[it->second][j].second)); } s.erase(it); while (s.size()>=kk-i+1) it=s.end(),--it,s.erase(it); } for (int i = 1; i <= q; i++) printf("%lld\n", ans[Q[i]]); } return 0; }
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+10; int n,m; deque<int>q; int a[maxn],ans[maxn],vis[maxn],x,k; int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } for (int i = 1; i <= m; i++) { scanf("%d", &x); q.push_front(x); } while (!q.empty()) { int x = q.front(); if (vis[x] == 0) ans[k++] = x; q.pop_front(); vis[x] = 1; } for (int i = 1; i <= n; i++) { if (vis[i] == 0) { ans[k++] = i; } } for (int i = 0; i < k; i++) { printf("%d ", ans[i]); } //printf("\n"); }