1 #include2 using namespace std; 3 inline int read(){ 4 register int x=0,f=1;char ch=getchar(); 5 while(!isdigit(ch)) f=ch=='-'?-1:1,ch=getchar(); 6 while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-48,ch=getchar(); 7 return x*f; 8 } 9 int n,m,cnt; 10 int a[205],buc[205],tmp[20000005]; 11 int main(){//freopen("text.in","r",stdin);freopen("b.out","w",stdout); 12 n=read(),m=read(); 13 for(int i=1;i<=m;++i){ 14 a[i]=read(); 15 for(int j=1;j*j<=a[i];++j){ 16 if(a[i]%j) continue; 17 tmp[++cnt]=j; 18 if(j*j!=a[i]) tmp[++cnt]=a[i]/j; 19 } 20 } 21 sort(tmp+1,tmp+cnt+1); 22 cnt=unique(tmp+1,tmp+cnt+1)-(tmp+1); 23 for(int i=1;i<=cnt;++i){ 24 if(tmp[i]>n) break; 25 int cnt=0; 26 for(int j=1;j<=m;++j) 27 if(a[j]%tmp[i]==0) cnt++; 28 buc[cnt]++; 29 } 30 buc[0]=n; 31 for(int i=1;i<=m;++i) buc[0]-=buc[i]; 32 for(int i=0;i<=m;++i) printf("%d\n",buc[i]); 33 return 0; 34 }
1 #include2 #define int long long 3 #define N 305 4 #define M 100005 5 using namespace std; 6 inline int read(){ 7 register int x=0,f=1;char ch=getchar(); 8 while(!isdigit(ch)) f=ch=='-'?-1:1,ch=getchar(); 9 while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-48,ch=getchar(); 10 return x*f; 11 } 12 struct store{int c,v,t;}s[N]; 13 bool cmp1(const store &a,const store &b){return a.t<b.t;} 14 struct query{int t,m,id;}q[M]; 15 bool cmp2(const query &a,const query &b){return a.t<b.t;} 16 int n,m,MAXV; 17 int f[90005],Min[90005],ans[M]; 18 signed main(){//freopen("text.in","r",stdin);freopen("b.out","w",stdout); 19 n=read(),m=read(); 20 for(int i=1;i<=n;++i) s[i].c=read(),s[i].v=read(),s[i].t=read(),MAXV=max(MAXV,s[i].v); 21 sort(s+1,s+n+1,cmp1); 22 for(int i=1;i<=m;++i) q[i].t=read(),q[i].m=read(),q[i].id=i; 23 sort(q+1,q+m+1,cmp2); 24 MAXV*=n; 25 memset(f,0x3f,sizeof f); 26 memset(Min,0x3f,sizeof Min); 27 f[0]=0; 28 int tail=1; 29 for(int j=1;j<=m;++j){ 30 while(tail<=n&&s[tail].t<=q[j].t){ 31 int Val=s[tail].v,Cost=s[tail].c; 32 for(int i=MAXV;i>=Val;--i) 33 f[i]=min(f[i],f[i-Val]+Cost); 34 Min[MAXV]=f[MAXV]; 35 for(int i=MAXV-1;~i;--i) Min[i]=min(Min[i+1],f[i]); 36 tail++; 37 } 38 int l=0,r=MAXV; 39 while(l<r){ 40 int mid=l+r+1>>1; 41 if(Min[mid]<=q[j].m) l=mid; 42 else r=mid-1; 43 } 44 ans[q[j].id]=l; 45 } 46 for(int i=1;i<=m;++i) printf("%lld\n",ans[i]); 47 return 0; 48 }
1 #include2 #define N 70005 3 4 using namespace std; 5 6 inline int read(){ 7 register int x=0,f=1;char ch=getchar(); 8 while(!isdigit(ch)) f=ch=='-'?-1:1,ch=getchar(); 9 while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-48,ch=getchar(); 10 return x*f; 11 } 12 13 struct Node{ 14 int u,v; 15 }zj[N]; 16 17 struct SB{ 18 Node u,v; 19 int laslen,zjlen,lstRk; 20 }sta[N*20]; 21 22 int n,m,top,maxlen; 23 int fa[N],Rk[N],ans[N],zjlen[N]; 24 25 struct Tree{ 26 int B,C,head[N],to[N<<1],nxt[N<<1],dep[N],Log[N<<1],R[N<<1],ver[N<<1],first[N<<1],f[25][N<<1]; 27 inline void link(int x,int y){to[++B]=y,nxt[B]=head[x],head[x]=B;} 28 inline void dfs(int x,int depth){ 29 dep[x]=depth; 30 ver[++C]=x,R[C]=depth,first[x]=C; 31 for(int i=head[x];i;i=nxt[i]) if(dep[to[i]]==0) dfs(to[i],depth+1),ver[++C]=x,R[C]=depth; 32 } 33 inline void init(){ 34 Log[0]=-1;for(int i=1;i<=n*2;++i) Log[i]=Log[i>>1]+1;dfs(1,1); 35 for(int i=1;i<=C;++i) f[0][i]=i; 36 for(int i=1;i<=Log[C];++i) 37 for(int j=1;j+(1<1<=C;++j) 38 f[i][j]=(R[f[i-1][j]] 1][j+(1< 1)]])?(f[i-1][j]):(f[i-1][j+(1< 1)]); 39 } 40 inline int LCA(int x,int y){ 41 x=first[x],y=first[y]; 42 if(x>y) swap(x,y); 43 int Logg=Log[y-x+1]; 44 int a=f[Logg][x],b=f[Logg][y-(1< 1]; 45 return R[a] ver[a]:ver[b]; 46 } 47 inline int Dis(const int &x,const int &y){return dep[x]+dep[y]-dep[LCA(x,y)]*2;} 48 }T; 49 50 struct Segment{ 51 #define lch k<<1 52 #define rch k<<1|1 53 vector vec[N<<2]; 54 55 int find(int x){return x==fa[x]?x:find(fa[x]);} 56 void Merge(const Node &x){ 57 // printf("开始合并bing~%d %d\n",x.u,x.v); 58 int u=x.u,v=x.v; 59 int fu=find(u),fv=find(v); 60 // printf("fu:%d fv:%d\n",fu,fv); 61 if(Rk[fu]<Rk[fv]) swap(u,v),swap(fu,fv); 62 if(fu==fv) return; 63 // puts("垃圾xuefeng"); 64 ++top; 65 sta[top]=(SB){(Node){fu,fv},zj[fu],maxlen,zjlen[fu],Rk[fu]}; 66 Rk[fu]=max(Rk[fu],Rk[fv]+1),fa[fv]=fu; 67 int a=zj[fu].u,b=zj[fu].v,c=zj[fv].u,d=zj[fv].v; 68 int na=a,nb=b,ZJ=zjlen[fu],NZJ; 69 NZJ=zjlen[fv];if(NZJ>ZJ) na=c,nb=d,ZJ=NZJ; 70 NZJ=T.Dis(a,c);if(NZJ>ZJ) na=a,nb=c,ZJ=NZJ; 71 NZJ=T.Dis(a,d);if(NZJ>ZJ) na=a,nb=d,ZJ=NZJ; 72 NZJ=T.Dis(b,c);if(NZJ>ZJ) na=b,nb=c,ZJ=NZJ; 73 NZJ=T.Dis(b,d);if(NZJ>ZJ) na=b,nb=d,ZJ=NZJ; 74 zj[fu]=(Node){na,nb},zjlen[fu]=ZJ,maxlen=max(maxlen,ZJ); 75 } 76 void Backto(int las){ 77 SB x; 78 while(top>las) 79 x=sta[top--],Rk[x.u.u]=x.lstRk,fa[x.u.v]=x.u.v,zj[x.u.u]=x.v,maxlen=x.laslen,zjlen[x.u.u]=x.zjlen; 80 } 81 Node A; 82 void ins(int k,int l,int r,int L,int R){ 83 // printf("L%d R:%d\n",L,R); 84 if(L<=l&&r<=R) return vec[k].push_back(A),void(); 85 int mid=l+r>>1; 86 if(L<=mid) ins(lch,l,mid,L,R); 87 if(R>mid) ins(rch,mid+1,r,L,R); 88 } 89 void fly(int k,int l,int r){ 90 int now=top; 91 for(int i=0;i<(int)vec[k].size();++i) Merge(vec[k][i]); 92 if(l==r) return ans[l]=maxlen,Backto(now),void(); 93 int mid=l+r>>1; 94 fly(lch,l,mid);fly(rch,mid+1,r); 95 Backto(now); 96 } 97 }S; 98 int main(){ 99 n=read(),m=read(); 100 for(int i=1;i i){ 101 int u=read(),v=read(),l=read(),r=read(); 102 S.A=(Node){u,v};S.ins(1,1,n,l,r); 103 T.link(u,v);T.link(v,u); 104 } 105 for(int i=1;i<=n;++i) fa[i]=i,Rk[i]=1,zj[i]=(Node){i,i},zjlen[i]=0; 106 T.init(); 107 S.fly(1,1,n); 108 // for(int i=1;i<=n;++i) printf("ans[%d]=%d\n",i,ans[i]); 109 for(int i=1;i<=m;++i) printf("%d\n",ans[read()]); 110 }
A. Divisors
把每个数的约数都扫一遍,排序去重。
然后在用每个约数在扫一遍所有的数看有几个数能整除它。
B. Market
首先时间的限制可以通过排序+一个指针解决。
其次我们观察到花费为1e9而价值只有300,考虑对过去的背包重新定义。
设f[]表示价值为i时的最小花费。f[i]=f[i-v]+c
接下来考虑我们每次询问都有个m是花费上限。
设g[]表示价值为i时的最小花费后缀最小值,即价值>=i的最小花费。
那么g[]数组一定是单调不下降的。考虑二分找答案。
具体就是二分mid是价值,然后判断g[mid]与m的关系即可。
C. Dash Speed
早读一直在卡常从T40卡成T60,后来改成ST表求LCA从7000ms快成1400ms。
对值域建树,把每条边拆成了log个节点,然后我们考虑答案就是所有覆盖这个叶子节点的节点的所有边组成的森林(树)中的最大直径。
通过并茶几维护边得到最大直径我们已经做过一道相关题目。
但是这样如果对每个叶子节点都这样操作,复杂度可达$O(n×m×log)$
因此考虑将上一次的并茶几拿来我用。也就是将一些边的贡献撤销掉。
考虑如何撤销。首先路径压缩无法使用了,因为它会破坏父子关系导致无法复原。
其次我们发现这道题其实并不是可耻就化并茶几,因为它的访问历史状态等价于直接到那个状态,而不用要其它状态或者复原。
所以我(题解)的做法是:将每一次Merge操作压入栈里,在刚进入这个线段树节点时记录栈的Top,然后将这个节点上的边实施Merge操作。
然后递归进入左右儿子。等回溯时,用Backto函数将Top返回到原来记录的Top,将里面的贡献全部消除。
为什么是正确的呢?因为你每次消除这条边就表示它一定是目前的Top,那么它就相当于刚刚Merge进去了,你在把它搞出来不就完了。
心疼我的早读用在了卡常上不过反正也是困死了
- 看到自己T不要老想着卡常,考虑几个更好的算法,有时候一个Log就用途很大。