zoukankan      html  css  js  c++  java
  • 20190907爆零记

    今天突然( m pdf)题面了,认真打了打,于是自闭了

    ( m T1)是个简单的结论题,给定(n,m,q),求([1,q])里不能被(n imes x+m imes y)表示的数有多少个

    一眼大凯的疑惑既视感

    首先设(r=(n,m)),能表示的数就一定是(r)的倍数,于是我们让(n=frac{n}{r},m=frac{m}{r}),求一下([1,left lfloor frac{q}{r} ight floor])内能被表示的数即可,让(q)减去这个数就是答案了

    注意到现在(nperp m),考虑小凯的疑惑中的结论,不能被表示的最大数是(n imes m-n-m),即一个数(c)能被表示,必定唯一存在(c=n imes x+m imes y),且(x<m,y<n)

    注意到(nleq 10^5,y<n),于是考虑枚举这个(y),于是在([m imes y,left lfloor frac{q}{r} ight floor])范围内所有(n)的倍数都能被表示出来,这样的数的个数显然有(left lfloor frac{(left lfloor frac{q}{r} ight floor-m imes y)}{n} ight floor +1)

    最后注意到(0)也被视为能表示的数了,减掉即可

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define re register
    #define LL long long
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int gcd(int a,int b) {
    	return !b?a:gcd(b,a%b);
    }
    int T,n,m;
    LL q;
    int main() {
    	freopen("simple.in","r",stdin);
    	freopen("simple.out","w",stdout);
    	scanf("%d",&T);
    	while(T--) {
    		scanf("%d%d%lld",&n,&m,&q);
    		if(n>m) std::swap(n,m);
    		int r=gcd(n,m);LL ans=q;
    		n/=r,m/=r,q/=r;
    		for(re int i=0;i<n&&1ll*m*i<=q;++i)
    			ans-=(q-1ll*m*i)/n,ans--;
    		printf("%lld
    ",ans+1);
    	}
    	return 0;
    }
    

    由于在最后二十分钟才推出结论而过于兴奋,让(q)(n imes m-n-m)取了一个(min),而(ans)的初值设成了(min)之后的(q),于是获得了(10 m pts)的好成绩

    ( m T2)给定一棵树,边有边权,长度都为(1),定义一条路径的架势为这条路径上所有边边权的(gcd),要求对于任意(iin[1,n]),求长度为(i)的路径的最大权值

    (nleq 4 imes 10^5,wleq 10^6)

    不难发现长度越小的路径,其最大权值也就越大,因此答案单调不降

    考虑一个(O(nw))的做法,即枚举(gcd),求当前(gcd)下的最长路径;每次只走边权为(i)的倍数的边,找树上直径即可

    这样每次跑一边整棵树太傻了,于是我们把边权为(i)的倍数的边都拿出来,跑树的直径即可,复杂度是所有边的约数个数和

    代码

    #include<bits/stdc++.h>
    #define re register
    #define max(a,b) ((a)>(b)?(a):(b))
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    std::vector<int> v[1000001];
    const int maxn=4e5+5;
    struct E{int v,nxt;}e[maxn<<1];
    int head[maxn],st[maxn],vis[maxn],top,num,cnt,n,T,tot;
    int rx[maxn],ry[maxn],ans[maxn],f[maxn],tax[maxn],dep[maxn];
    inline void add(int x,int y) {
    	e[++num].v=y;e[num].nxt=head[x];head[x]=num;
    	if(!vis[x]) st[++top]=x,vis[x]=1;
    }
    void dfs(int x,int fa,int o) {
    	if(o) f[x]=1,tax[++cnt]=x;
    	for(re int i=head[x];i;i=e[i].nxt) {
    		if(e[i].v==fa) continue;
    		dep[e[i].v]=dep[x]+1;
    		dfs(e[i].v,x,o);
    	} 
    }
    inline void getdis(int x) {
    	cnt=0;dep[x]=0;dfs(x,0,1);int rt=tax[1];
    	for(re int i=2;i<=cnt;++i) if(dep[tax[i]]>dep[rt]) rt=tax[i];
    	dep[rt]=0;dfs(rt,0,0);
    	for(re int i=1;i<=cnt;i++) tot=max(tot,dep[tax[i]]);
    }
    int main() {
    	n=read();
    	for(re int w,i=1;i<n;i++) {
    		rx[i]=read(),ry[i]=read();
    		w=read(),T=max(T,w);
    		v[w].push_back(i);
    	}
    	for(re int i=1;i<=T;++i,tot=0,num=0) {
    		for(re int j=i;j<=T;j+=i)
    			for(re int k=0;k<v[j].size();k++)
    				add(rx[v[j][k]],ry[v[j][k]]),add(ry[v[j][k]],rx[v[j][k]]);
    		for(re int j=1;j<=top;++j) {
    			if(f[st[j]]) continue;
    			getdis(st[j]);
    		}
    		ans[tot]=i;
    		while(top) f[st[top]]=vis[st[top]]=head[st[top]]=0,top--;
    	}
    	for(re int i=n-1;i;--i) ans[i]=max(ans[i],ans[i+1]);
    	for(re int i=1;i<=n;i++) printf("%d
    ",ans[i]);
    	return 0;
    }
    

    ( m T3)给定(n,L,s)和一个严格上升的数组({x_1,x_2,...,x_n}),需要求一个排列(p),满足(p_1=s),且(p_i<p_{i+1})恰有(L)项,最小化

    [sum_{i=2}^n|x_{p_i}-x_{p_{i-1}}| ]

    写了个假贪心之后果真假了,之后发现全场都假了

    看了看成爷的假贪心发现我们好像假的差不多,但是不知道为什么我(20 m pts)(35 m pts)

    正解非常巧妙

    不妨考虑(s=1)的情况,如果我们要从(s)走到(n),如果没有(L)的限制,最优的方案就是直接从(1)走过去,但是有了(L)的限制,就要求我们必须走一些回头路

    首先(1)(n)之间的所有线段都至少被经过了一次,由于我们必须走(L)次回头路,所有至少有(L)(x_i-x_{i-1})额外经过了两次,即从前面走回来再走回去,所以(1)走到(n)中间需要走(L)次回头路的最小花费就是(x_n-x_1),加上前(L)小的(x_i-x_{i-1}),显然(L)越小这个花费也就越小

    再来考虑终点不在(n)的情况,考虑枚举一个终点(e),那么在([1,s])([e,n])这两段里要花费的(L)次数就是(s-1+n-e),同时里面的这些线段也会被经过两次

    这样在两边的花费都尽量小,同时还能减小在([s,e])之间需要花费的(L)的次数;这个时候我们发现([s,e])的情况和([1,n])的情况是等价的,也就是也就是说我们需要维护([s,e])之间前(L-s+1-n+e)小的(x_i-x_{i-1})

    随着(e)的增大,我们发现影响的只有(x_{e}-x_{e-1})这一条线段,于是我们用一个堆就能维护了

    代码就不写了

    从这次考试还是能看出自己非常垃圾了,首先就是在没有大样例的情况下挂题的概率趋近于1,还懒得去写暴力和搭拍,于是往往搞出来的题也挂的非常惨

    时间分配上也非常弟弟,( m T3)的假贪心写了一个多小时,( m T1)推到最后才写出来,留给( m T2)的时间就只够写个暴力了

    之后还是智商太低了,( m T1)这样的结论题,成爷(10 m min)就切了,我这种睿智选手搞到最后半个小时才搞出来,之后还写挂了;( m T3)的贪心还看不出来假了,于是兴致盎然的写了好久

    看来下次得对着成爷的屏幕白嫖了

  • 相关阅读:
    字典的增删改查
    基础数据类型
    Linux程序优化实践
    Linuxt性能调优指南
    【MySQL】Percona Toolkits工具介绍及使用
    【MySQL】如何构建高性能MySQL系统?
    【MySQL】Event使用案例
    【MySQL】事件调度器 (Event Scheduler)
    【MySQL】mydumper工具介绍
    spu与sku的含义
  • 原文地址:https://www.cnblogs.com/asuldb/p/11484665.html
Copyright © 2011-2022 走看看