10 9

  又挂题了233..我 已经无力了 就是因为手懒少写了一个对拍 觉得 大样例都过了以为不可能挂 还是细节翻了车。以后我绝不后退 绝不懒惰 我腰板 还能挺直。

痛苦良久../kk 还是多休息的好 我可能写了一下午题太累了导致晚上什么也不想干 也不想思考的缘故。

今天得分 185 T1 100分 T2 85分 T3 0分

要求出最大的公约数 爆搜好啊 发现效率并不高 考虑枚举最大公约数 复杂度 ai*n 

每个我们没有必要判断一个数字是否有ai 只需要把n分解出来再判断ai 即可 这里有nlogn的做法 调和级数的证明方法 叫做倍数法 但是不如n*sqrt(n) 写的快也能通过本题。

加一些细节判断即可。

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<algorithm>
#include<vector>
#include<cctype>
#include<cstdlib>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#define INF 1000000000
#define ll long long
#define min(x,y) ((x)>(y)?(y):(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define db double
#define EPS 1e-8
using namespace std;
char *fs,*ft,buf[1<<15];
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const int MAXN=100010,maxn=1000010;
int n,maxx;
int a[MAXN];
int w[maxn],ans[MAXN],p[MAXN];
inline void fj(int x)
{
    for(int i=2;i*i<=x;++i)
    {
        if(x%i==0)
        {
            ++w[i];
            int v=x/i;
            if(v!=i)++w[v];
        }
    }
    ++w[1];++w[x];
}
int main()
{
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    freopen("group.in","r",stdin);
    freopen("group.out","w",stdout);
    n=read();
    for(int i=1;i<=n;++i)
    {
        a[i]=read();
        fj(a[i]);
        maxx=max(maxx,a[i]);
    }
    for(int i=maxx;i;--i)
        if(!ans[w[i]])ans[w[i]]=i;
    int last=1;
    for(int i=n;i;--i)
    {
        p[i]=max(last,ans[i]);
        last=p[i];
    }
    for(int i=1;i<=n;++i)printf("%d\n",p[i]);
    return 0;
}
View Code

发现 我们只要得到人的集合 并成功到达终点即可 装压一下 压到队列里然后开始暴力dij 复杂度 n*2^k*logn 只有50分。

考虑优化 发现 对于一些没有队友的地方没有必要设立状态每次除了到终点 一定从 一个地方到一个有队友的地方我们只考虑保留这些状态即可。

发现可以枚举全排列暴力判断 复杂度 k! 继续优化 发现可以状压进行状态间的合并从而降低复杂度 2^k*k*k 就这样可以通过本题。

一个比较细节的地方是一个地方可能有两个人我虽然想到了但是细节处理的时候最终状态是 2^top-1 但是写成了 2^k-1 导致完挂。

我是真的菜 真的是sb 为什么不对拍 为什么 不仔细静态查错 为什么不自己手玩几组数据  我是个弱智吧,还能犯这种低级错误。

如果我肯对拍 如果我构造数据了数据这种事情是不可能发生的 都怪我太蠢了 没有经过对拍的代码 就是0分。

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<algorithm>
#include<vector>
#include<cctype>
#include<cstdlib>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#define INF 10000000000000000ll
#define inf 1000000100
#define ll long long
#define min(x,y) ((x)>(y)?(y):(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define db double
#define EPS 1e-5
#define PII pair<int,int>
#define mk make_pair
using namespace std;
char *fs,*ft,buf[1<<15];
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const int MAXN=50010,MAX=21;
int n,m,k,st,len,maxx,top;
int a[MAXN],b[MAXN],w[MAX],vis[MAXN];//a表示第i个地方是否是出口 b表示第i个地方存在的同伴集合
int lin[MAXN],nex[MAXN<<1],ver[MAXN<<1],e[MAXN<<1];
int dis[MAXN],c[MAX][MAX];
ll f[1<<MAX][MAX],ans=INF;//f[i][j]表示到了集合为i到了第j个点的最小代价;
priority_queue<PII> q;
inline void add(int x,int y,int z)
{
    ver[++len]=y;
    nex[len]=lin[x];
    lin[x]=len;
    e[len]=z;
}
inline void prepare(int x)
{
    for(int i=1;i<=n;++i)dis[i]=inf,vis[i]=0;
    dis[x]=0;q.push(mk(-dis[x],x));
}
inline void dij()
{
    while(q.size())
    {
        int x=q.top().second;
        q.pop();
        if(vis[x])continue;
        vis[x]=1;
        for(int i=lin[x];i;i=nex[i])
        {
            int tn=ver[i];
            if(dis[tn]>dis[x]+e[i])
            {
                dis[tn]=dis[x]+e[i];
                q.push(mk(-dis[tn],tn));
            }
        }
    }
}
int main()
{
    //freopen("1.in","r",stdin);
    freopen("maze.in","r",stdin);
    freopen("maze.out","w",stdout);
    n=read();m=read();k=read();st=read();
    for(int i=1;i<=n;++i)a[i]=read();
    for(int i=1;i<=m;++i)
    {
        int x,y,z;
        x=read();y=read();z=read();
        if(x==y)continue;
        add(x,y,z);add(y,x,z);
    }
    for(int i=1;i<=k;++i)++b[read()];
    for(int i=1;i<=n;++i)if(b[i])w[++top]=i;
    maxx=(1<<top)-1;
    for(int i=1;i<=top;++i)
    {    
        prepare(w[i]);dij();
        for(int j=1;j<=top;++j)c[i][j]=dis[w[j]];
    }
    prepare(st);dij();
    memset(f,-1,sizeof(f));
    for(int i=1;i<=top;++i)f[1<<(i-1)][i]=dis[w[i]];
    for(int i=1;i<maxx;++i)
    {    
        ll sum=1;
        for(int j=1;j<=top;++j)if(i&(1<<(j-1)))sum+=b[w[j]];
        for(int j=1;j<=top;++j)
        {
            if(f[i][j]<0)continue;
            for(int k=1;k<=top;++k)
            {
                if(i&(1<<(k-1)))continue;
                int s=i|(1<<(k-1));
                if(f[s][k]<0)f[s][k]=INF;
                f[s][k]=min(f[s][k],f[i][j]+c[j][k]*sum);
            }
        }
    }
    for(int i=1;i<=n;++i)
    {
        dis[i]=inf;vis[i]=0;
        if(a[i])
        {
            q.push(mk(0,i));
            dis[i]=0;
        }
    }
    dij();
    for(int i=1;i<=top;++i)ans=min(ans,(ll)(k+1)*dis[w[i]]+f[maxx][i]);
    printf("%lld\n",ans);
    return 0;
}
View Code

这道题是整场比赛的败笔 我可能当时心态爆炸 两个h写这道题看到100分这么大瞬间就不是很想写了 想直接70分暴力算了。当站在这个角度我就没有好好分析题目的性质。

最后写了2h 得分0. 我不太清楚 写了两个暴力一个50分 一个30分 双双挂掉 我不太清楚?!都接近150行 代码复杂度较高。
却怎么也调不出来了 。我应该多思考一下看有没有巧妙的做法的 不可能是那么复杂的东西的性质没有发现写的太多东西都是在浪费时间。

不如 2h我什么都不写只思考 这样也是0分省事 所以 一定要有一个比较宏观的想法 和 一些比较容易实现的思路再写。

多窥探20分链的情况和100分的做法 可以加快对题目的理解。而不是纠结于一道题的暴力做法的细节处理 可能不需要处理那么多只是未曾发现性质。

考虑这道题目怎么做?写了几个h 发现自己读错题了 又读错题了 要是我读出的那种题目的确非常难以判断。

都有 读成都是 两个词可并不一样。有点爆炸 思路有点混乱 下午填坑。

我 缓过来了 开始证明这个东西 服了  观察一下两条链有公共边且 一条链的LCA 上方有另外一条链上的点。

这也就形成了 上面有点下面也有点 他们是同一条链 的下面的点跳到上面有且只有一种方法就是不断的向上跳。

所以可以推出 这条链的LCA 必然下方有一条边是 另外一条链的 上方也有一条边。如此简单的判定。

暴力其实就是这样当然下方的边必然是x 那一支或者y的那一支 否则肯定是不交的。复杂度 m^2logn (logn 倍增向上跳)

考虑正解 其实 我么发现一条产生的链我们只单纯考虑了LCA 而且判定成功的点其实就是LCA下方的点和x 或y在同一脉的点 不妨 考虑把权值挂到某个点上这样我们就可以通过统计树上的边从而快速统计答案。

其实我们只要把权放到LCA下方的两条边上即可 这样可以通过访问一条链的权值 来统计答案 实际上 是x 到 xx  y到yy。

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<algorithm>
#include<vector>
#include<cctype>
#include<cstdlib>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#define INF 1000000010
#define ll long long
#define min(x,y) ((x)>(y)?(y):(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define db double
#define EPS 1e-5
using namespace std;
char *fs,*ft,buf[1<<15];
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const int MAXN=100010;
int n,m,ans,top,len=1,sum;
int f[MAXN][20],d[MAXN],Log[MAXN],vis[MAXN];
int lin[MAXN],nex[MAXN],ver[MAXN];
int g[MAXN][20];
inline void add(int x,int y)
{
    ver[++len]=y;
    nex[len]=lin[x];
    lin[x]=len;
}
struct wy{int x,y,z,lca,xx,yy;}t[MAXN];
inline int cmp(wy a,wy b){return a.lca<b.lca;}
inline void dfs(int x)
{
    for(int i=lin[x];i;i=nex[i])
    {
        int tn=ver[i];
        d[tn]=d[x]+1;
        for(int j=1;j<=Log[d[tn]];++j)
            f[tn][j]=f[f[tn][j-1]][j-1];
        dfs(tn);
    }
}
inline void dfs1(int x)
{
    for(int i=lin[x];i;i=nex[i])
    {
        int tn=ver[i];
        for(int j=1;j<=Log[d[tn]];++j)
            g[tn][j]=g[tn][j-1]+g[f[tn][j-1]][j-1];
        dfs1(tn);
    }
}
inline int LCA(int x,int y)
{
    if(d[x]<d[y])swap(x,y);
    for(int i=Log[d[x]];i>=0;--i)
        if(d[f[x][i]]>=d[y])x=f[x][i];
    if(x==y)return x;
    for(int i=Log[d[x]];i>=0;--i)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
inline int getx(int x,int y)
{
    if(y==0)return x;
    for(int i=0;i<=Log[y];++i)
        if((1<<i)&y) x=f[x][i];
    return x;
}
inline int get_x(int x,int y)
{
    for(int i=Log[d[x]];i>=0;--i)
        if(d[f[x][i]]>=y)x=f[x][i];
    return x;
}
inline int get(int x,int y)
{
    int cnt=0;
    for(int i=Log[d[x]];i>=0;--i)
        if(d[f[x][i]]>=d[y])
        {    
            cnt+=g[x][i];
            x=f[x][i];
        }
    return cnt;
}
int main()
{
    freopen("1.in","r",stdin);
    n=read();m=read();d[1]=1;
    for(int i=2;i<=n;++i)
    {
        f[i][0]=read();
        add(f[i][0],i);
        Log[i]=Log[i>>1]+1;
    }
    dfs(1);
    for(int i=1;i<=m;++i)
    {
        int x,y,z,xx=0,yy=0;
        x=read();y=read();z=read();
        if(x==y){ans=max(ans,z);continue;}
        int lca=LCA(x,y);
        //cout<<lca<<endl;
        if(d[x]<d[y])swap(x,y);
        if(y==lca)//xx=get_x(x,d[y]+1);    
        xx=getx(x,d[x]-d[y]-1);
        else //xx=get_x(x,d[lca]+1),yy=get_x(y,d[lca]+1); 
        xx=getx(x,d[x]-d[lca]-1),yy=getx(y,d[y]-d[lca]-1);
        g[xx][0]+=z;g[yy][0]+=z;
        //cout<<getx(x,d[x]-d[y]-1)<<endl;
        //cout<<g[lca][0]<<' '<<lca<<' '<<t[i].z<<endl;
        t[++top]=(wy){x,y,z,lca,xx,yy};
    }
    dfs1(1);
    for(int i=1;i<=top;++i)
    {
        int x=t[i].x;
        int y=t[i].y;
        int cnt=t[i].z;
        if(d[x]>d[t[i].xx])cnt+=get(x,t[i].xx);
        if(d[y]>d[t[i].yy]&&t[i].yy)cnt+=get(y,t[i].yy);
        ans=max(ans,cnt);
    }
    printf("%d\n",ans);
    return 0;
}
View Code

那么 这一天的模拟赛也结束了 离我离去不远了..

posted @ 2019-10-10 10:37  chdy  阅读(672)  评论(0编辑  收藏  举报