A. k-Factorization
题目大意:给一个数n,求k个大于1的数,乘积为n。(n<=100,000,k<=20)
思路:分解质因数呗
#include<cstdio> #define MN 100000 int a[MN+5],an; int main() { int n,k,i; scanf("%d%d",&n,&k); for(i=2;k>1&&n>1;++i)for(;k>1&&n%i==0;--k,n/=i)a[++an]=i; if(n==1)return 0*puts("-1"); for(i=1;i<=an;++i)printf("%d ",a[i]);printf("%d",n); }
B. Odd sum
题目大意:给你n个数,求和为奇数的子序列的最大和。(n<=10^5)
思路:大于0的偶数直接加入答案,把奇数排序,先选一个最大的把它删掉并加入答案,while剩下的最大的的两个奇数和大于0就加入答案并删掉。
#include<cstdio> #include<algorithm> using namespace std; char B[1<<26],*S=B,C;int X,F; inline int read() { for(F=1;(C=*S++)<'0'||C>'9';)if(C=='-')F=-1; for(X=C-'0';(C=*S++)>='0'&&C<='9';)X=(X<<3)+(X<<1)+C-'0'; return X*F; } #define MN 100000 int a[MN+5],an; int main() { fread(B,1,1<<26,stdin); int n=read(),i,x,ans=0; for(i=1;i<=n;++i) if((x=read())&1)a[++an]=x; else if(x>0)ans+=x; sort(a+1,a+an+1); ans+=a[an]; for(i=an;--i>1;--i)if(a[i]+a[i-1]>0)ans+=a[i]+a[i-1];else break; printf("%d",ans); }
C. Minimal string
题目大意:给出一个序列的入栈顺序,求字典序最小的可能的出栈顺序。(序列长度<=10^5)
思路:堆+双向链表贪心,选了一个元素后之后只能选这个元素的前一个元素和后面的元素,每次选能选的最小且位置最前的。
#include<cstdio> #include<cstring> #include<queue> using namespace std; #define MN 100000 char s[MN+5]; int ls[MN+5],nx[MN+5],u[MN+5]; struct node { char c;int x; bool operator<(const node&b)const{return c==b.c?x>b.x:c>b.c;} }; priority_queue<node> pq; int main() { int n,i,l,x; scanf("%s",s+1);n=strlen(s+1); for(i=1;i<=n;++i)ls[i]=i-1,nx[i]=i+1,pq.push((node){s[i],i}); for(i=l=1;i<=n;++i) { while((x=pq.top().x)<l||u[x])pq.pop(); u[x]=1;putchar(pq.top().c);pq.pop(); if(ls[x]<l&&ls[x])pq.push((node){s[ls[x]],ls[x]}); l=ls[x];nx[ls[x]]=nx[x];ls[nx[x]]=ls[x]; } }
D. Broken BST
题目大意:给出一棵n个节点的树,每一个点有一个权值,对每个点的权值从根节点开始按二叉搜索树的方式查询,问有多少个点的权值不会被查到。(n<=10^5)
思路:dfs求出会走到每个节点的数字区间。
#include<cstdio> #include<map> using namespace std; char B[1<<26],*S=B,C;int X,F; inline int read() { for(F=1;(C=*S++)<'0'||C>'9';)if(C=='-')F=-1; for(X=C-'0';(C=*S++)>='0'&&C<='9';)X=(X<<3)+(X<<1)+C-'0'; return X*F; } #define MN 100000 #define MX 1000000000 int v[MN+5],l[MN+5],r[MN+5],d[MN+5]; map<int,int> mp; void dfs(int x,int L,int R) { if(x<0)return; if(L<=v[x]&&v[x]<=R)mp[v[x]]=1; if(L<v[x])dfs(l[x],L,min(R,v[x]-1)); if(R>v[x])dfs(r[x],max(L,v[x]+1),R); } int main() { fread(B,1,1<<26,stdin); int n=read(),i,ans=0; for(i=1;i<=n;++i)v[i]=read(), (l[i]=read())>0?++d[l[i]]:0, (r[i]=read())>0?++d[r[i]]:0; for(i=1;i<=n;++i)if(!d[i])dfs(i,0,MX); for(i=1;i<=n;++i)if(!mp[v[i]])++ans; printf("%d",ans); }
E. Array Queries
题目大意:给出n和ai(1<=i<=n),一次变换定义为把p变成p+a[p]+k,q次询问,每次给出p和k,问要多少次能把p变成大于n的数。(n,q<=10^5)
思路:分块,对于k<=n^0.5直接预处理出各个p和k的答案,对于k>n^0.5答案最大不会超过n^0.5,直接暴力,复杂度O(n^1.5)。
#include<cstdio> inline int read() { int x;char c; while((c=getchar())<'0'||c>'9'); for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0'; return x; } #define MN 100000 #define MK 350 int a[MN+5],f[MK+5][MN+5]; int main() { int n=read(),q,i,k,ans; for(i=1;i<=n;++i)a[i]=read(); for(k=1;k<=MK;++k)for(i=n;i;--i)f[k][i]=i+a[i]+k>n?1:f[k][i+a[i]+k]+1; for(q=read();q--;) { i=read();k=read(); if(k<=MK)printf("%d ",f[k][i]); else{for(ans=0;i<=n;i+=a[i]+k)++ans;printf("%d ",ans);} } }
F. Mice and Holes
题目大意:n只老鼠m个洞分别位于数轴上,每个洞有容量ci,求每个老鼠都进洞的最小距离和。(n,m<=5,000)
思路:把老鼠和洞分别排序,最优方案下进每个洞的老鼠必然是连续的区间,f[i][j]表示前i个洞进前j只老鼠的最小距离和,s[i][j]表示前j只老鼠都进第i个洞的距离和,f[i][j]=min(f[i-1][k]+s[i][j]-s[i][k])(j-k<=ci),单调队列维护即可,复杂度O(nm)。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define MN 5000 struct hole{int p,c;}h[MN+5]; bool cmp(hole a,hole b){return a.p<b.p;} int x[MN+5],q[MN+5],ql,qr; ll f[MN+5][MN+5],s[MN+5]; inline int z(int x){return x<0?-x:x;} int main() { int n,m,i,j;ll cnt=0; scanf("%d%d",&n,&m); for(i=1;i<=n;++i)scanf("%d",&x[i]); for(i=1;i<=m;++i)scanf("%d%d",&h[i].p,&h[i].c),cnt+=h[i].c; if(cnt<n)return 0*puts("-1"); sort(x+1,x+n+1);sort(h+1,h+m+1,cmp); memset(f,42,sizeof(f));f[0][0]=0; for(i=1;i<=m;++i)for(q[ql=1,qr=0]=j=0;j<=n;++j) { s[j]=s[j-1]+z(h[i].p-x[j]); while(ql<=qr&&f[i-1][j]-s[j]<=f[i-1][q[qr]]-s[q[qr]])--qr;q[++qr]=j; while(j-q[ql]>h[i].c)++ql; f[i][j]=f[i-1][q[ql]]+s[j]-s[q[ql]]; } printf("%I64d",f[m][n]); }