Educational Codeforces Round#19
来自FallDream的博客,未经允许,请勿转载,谢谢。
A. k-Factorization
给出n和k,问n能不能分成k个大于1的数字的乘积,输出方案。n<=100000 k<=20
直接分解质因数,k大于质因数数量时候无解,其他时候随便搞成k个输出就行了。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cmath> #include<set> #include<map> #define INF 2000000000 #define ll long long using namespace std; inline int read() { int x = 0; char ch = getchar(); while(ch < '0' || ch > '9')ch = getchar(); while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x; } int n,num,s[12313],k; int main() { n=read();k=read(); for(int i=2;n>1;i++) while(n%i==0) n/=i,s[++num]=i; if(num<k)return 0*puts("-1"); for(int i=k+1;i<=num;i++) s[k]*=s[i]; for(int i=1;i<=k;i++) cout<<s[i]<<" "; return 0; }
B. Odd sum
给定n个数,你要选出一个子序列,满足和是奇数且最大。n<=10^5
对于偶数显然把大于0的全选即可,奇数特判一下各种情况,如果大于0的数量是偶数,不选最小的;不然如果没有大于0的,选一个最大的。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cmath> #include<set> #include<map> #define INF 2000000000 #define ll long long using namespace std; inline int read() { int x = 0,f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = 0;ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return f?x:-x; } int n,s[100005],ans=0,mn=INF,mx=-INF,num=0; bool flag=false; int main() { n=read(); for(int i=1;i<=n;i++)s[i]=read(); for(int i=1;i<=n;i++) { if(s[i]>0) { if(!(s[i]&1)) ans+=s[i]; else flag=true,ans+=s[i],num++,mn=min(mn,s[i]); } else if(s[i]&1) mx=max(mx,s[i]); } if(!flag) ans+=mx; else if(!(num&1)) ans+=max(mx,-mn); cout<<ans; return 0; }
C.Minimal string
你有一个字符串s,你每次可以选择一种操作1
1)把s最前面的那个字符入栈 2)输出栈顶的字符,弹掉它。 你要让输出的字符串字典序最小。 |s|<=10^5
题解:拿一个堆,把所有字符都塞进去,另外维护一个栈顶的位置。每次先把堆里面在栈顶左边的全部弹掉,然后找出堆里面最小的中最靠前的,和栈顶对比,如果它比栈顶小,那么选择它,他们之间的字符全部入栈,否则就出栈。这样一定能找到最小的字符串。实现的话 再上一个双向链表吧 复杂度nlogn
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cmath> #include<set> #include<map> #define INF 2000000000 #define MN 100000 #define ll long long using namespace std; inline int read() { int x = 0,f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = 0;ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return f?x:-x; } char st[MN+5]; struct node { int x,pos; bool operator<(const node&b)const{return x==b.x?pos>b.pos:x>b.x;} }; priority_queue<node> q; int pos,ne[MN+5],la[MN+5],now; bool mark[MN+5]; void del(int x) { mark[x]=1; la[ne[x]]=la[x]; ne[la[x]]=ne[x]; } int main() { scanf("%s",st+1); for(int i=1;st[i];++i) q.push((node){st[i]-'a',i}); for(int i=1;st[i];i++) ne[i]=i+1,la[i]=i-1; while(!q.empty()) { while(!q.empty()&&q.top().pos<pos) q.pop(); if(q.empty()) break; int x=q.top().x; if(now&&x>=st[now]-'a') printf("%c",st[now]),del(now),now=la[now]; else { pos=q.top().pos;printf("%c",q.top().x+'a'); del(pos);now=la[pos];q.pop(); } } for(;pos;pos--) if(!mark[pos])printf("%c",st[pos]); return 0; }
D.Broken BST
你有一个数组,并且把它建成了一棵假的二叉搜索树,然后你把每个数组里面的数字都查一遍,问有多少个数字查不到。n<=100000
直接模拟线段树查数值,并且把能查到的数值全部用map记下来,最后每个数字去map里面找一下就行了。复杂度nlogn
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cmath> #include<set> #include<map> #define INF 2000000000 #define MN 100000 #define ll long long using namespace std; inline int read() { int x = 0,f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = 0;ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return f?x:-x; } int n,L[MN+5],R[MN+5],s[MN+5],in[MN+5],ans=0; map<int,bool> mp; void dfs(int x,int l,int r) { if(s[x]>=l&&s[x]<=r) mp[s[x]]=1; if(L[x]!=-1) dfs(L[x],l,min(s[x]-1,r)); if(R[x]!=-1) dfs(R[x],max(l,s[x]+1),r); } int main() { n=read(); for(int i=1;i<=n;i++) { s[i]=read();L[i]=read();R[i]=read(); if(L[i]!=-1) in[L[i]]++; if(R[i]!=-1) in[R[i]]++; } for(int i=1;i<=n;i++) if(!in[i]) dfs(i,0,INF); for(int i=1;i<=n;i++) if(!mp[s[i]]) ans++; cout<<ans; return 0; }
E. Array Queries
给定n个数ai,m个询问,每次给出p,k,然后每当p小等于n的时候,p就变成p+ap+k,问这个变化的次数 n,m<=100000 1<=ai,p,k<=n
对于k<=$\sqrt{n}$的询问,我们预处理答案,k更大的,显然次数不会超过根号次,暴力跳. 复杂度$O(n^{\frac{3}{2}})$
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cmath> #include<set> #include<map> #define INF 2000000000 #define MN 100000 using namespace std; inline int read() { int x = 0,f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = 0;ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return f?x:-x; } int num[350][MN+5],n,mx,m,s[MN+5]; int main() { n=read();mx=sqrt(n); for(int i=1;i<=n;i++)s[i]=read();m=read(); for(int i=0;i<=mx;i++) for(int j=n;j;--j) num[i][j]=num[i][min(n+1,j+s[j]+i)]+1; for(int i=1;i<=m;i++) { int x=read(),k=read(); if(k>mx) { int sum=0; for(;x!=n+1;x=min(n+1,x+s[x]+k)) ++sum; printf("%d\n",sum); } else printf("%d\n",num[k][x]); } return 0; }
F. Mice and Holes
有n只老鼠,m个洞,老鼠和洞在一个数轴上,且都有一个坐标,每个洞有最大容量ci。第i只老师进到第j个洞的费用是他们之间的距离,求最小费用。n,m<=5000
用f[i][j]表示前i只老鼠进到前j个洞的最小费用,s[i][j]表示前i只老鼠都到第j个洞的总费用
那么f[i][j]=min(f[k][j-1]+s[i][j]-s[k][j]),i-k<=cj
发现这个式子中s[i][j]是不变的,所以我们开一个单调队列维护就行了。复杂度O(nm)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define pa pair<ll,int> #define mp(x,y) make_pair(x,y) #define ll long long #define MN 5000 #define INF 200000000000000000LL using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } int n,m,x[MN+5]; ll f[2][MN+5],s[MN+5][MN+5]; struct hole { int x,c; bool operator<(const hole&b)const{return x<b.x;} }y[MN+5]; struct MyQueue { int top,tail;pa q[MN+5]; void clear(){q[top=tail=0]=mp(0,0);} void push(ll x,int pos) { while(top>=tail&&x<=q[top].first) --top; q[++top]=mp(x,pos); } ll get(int pos) { while(top>=tail&&q[tail].second<pos) ++tail; if(top<tail) return INF; return q[tail].first; } }q; inline int abs(int x){return x<0?-x:x;} int main() { memset(f,127,sizeof(f)); n=read();m=read(); for(int i=1;i<=n;i++) x[i]=read(); for(int i=1;i<=m;i++) y[i].x=read(),y[i].c=read(); sort(x+1,x+n+1);sort(y+1,y+m+1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) s[i][j]=s[i-1][j]+abs(x[i]-y[j].x); f[0][0]=0; for(int j=1,now=1,pre=0;j<=m;j++) { q.clear(); for(int i=1;i<=n;i++) { f[now][i]=q.get(i-y[j].c)+s[i][j]; q.push(f[pre][i]-s[i][j],i); f[now][i]=min(f[now][i],f[pre][i]); } now^=1;pre^=1;memset(f[now],127,sizeof(f[now])); } printf("%lld\n",f[m&1][n]<INF?f[m&1][n]:-1); return 0; }