【codevs10月月赛(第三次)】day 1

codevs第三次月赛

T1正解,T2部分分,T3迭代深搜……
结果:T1:100,T2:40,T3:40
rank25…其实T3的想法挺接近70分算法的,然而我还是打的暴力…还是太弱

T1:Cww的作业

打表可得:fn=n/2(下取整)

于是答案是2∑k^2(1<=k<=n)%10007

公式可知,答案是(n(n+1)(2n+1)/3) %10007

带除法的模,要求3的逆元,也就是求3x=1(%10007)的x,可以暴力for,也可以exgcd。

或者不用求逆元,n or n+1 or 2n+1 其中必有一个为3的倍数,找出来先除了再模也可以。

据说把n先模10007可以(玄学?)??我没试

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const long long mod=10007;

int main()
{
    long long n;
    scanf("%lld",&n);
    printf("%lld",( (n%mod) * ((n+1)%mod) * ((2ll*n+1)%mod) *3336ll)%10007); 

    return 0;
}

T2:逃离异次元杀阵

第一眼看:树,仙人掌,仙人掌加一条边…
然后就交了个倍增LCA,30分跑的暴力,拿40滚粗…

结果正解看起来好傻X…以下来自官方题解:
对于M=N的数据,考虑在原算法上进行修改。可以拆掉一条边使得其变为一棵树,设拆掉的边为x—y,权值为s,则依然按上述做法求解,则最终的答案是min{dis(i,j),dis(i,x)+s+dis(y,j),dis(i,y)+s+dis(x,j)}。拆边可以用各种方法完成。
对于M=N+1的数据,不过是多拆了一条边,不过是上述算法的加强版。设拆掉两条x1—y1,边权s1,x2—y2,边权s2,则答案是

min{
Dis(i,j)
Dis(i,x1)+s1+dis(y1,j)
Dis(i,x2)+s1+dis(y2,j)
Dis(i,y1)+s1+dis(x1,j)
Dis(i,y2)+s1+dis(x2,j)
Dis(i,x1)+s1+dis(y1,x2)+s2+dis(y2,j)
Dis(i,y1)+s1+dis(x1,x2)+s2+dis(y2,j)
Dis(i,x1)+s1+dis(y1,y2)+s2+dis(x2,j)
Dis(i,y1)+s1+dis(x1,y2)+s2+dis(x2,j)
Dis(i,x2)+s2+dis(y2,x1)+s1+dis(y1,j)
Dis(i,y2)+s2+dis(x2,x1)+s1+dis(y1,j)
Dis(i,x2)+s2+dis(y2,y1)+s1+dis(x1,j)
Dis(i,y2)+s2+dis(x2,y1)+s1+dis(x1,j)
}

时间复杂度是O(nlogn+13q)

滚粗代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int size=100010;
int head[size],nxt[size],dist[size],anc[size][32];
int tot=0;
int deep[size];
struct edge{
    int t,d;
}l[size];

void build(int f,int t,int d)
{
    l[++tot]=(edge){t,d};
    nxt[tot]=head[f];
    head[f]=tot;
}

void dfs(int u,int fa)
{
    if(deep[u]) return ;
    deep[u]=deep[fa]+1;
    anc[u][0]=fa;
    for(int i=1;anc[anc[u][i-1]][i-1];i++)
    {
        anc[u][i]=anc[anc[u][i-1]][i-1];
    }
    for(int i=head[u];i;i=nxt[i])
    {
        int v=l[i].t;
        if(!deep[v]) dist[v]=dist[u]+l[i].d;
        dfs(v,u);
    }
}

int asklca(int x,int y)
{
    if(deep[x]<deep[y]) swap(x,y);
    if(deep[x]>deep[y])
    {
        int dd=deep[x]-deep[y];
        for(int i=0;i<=28;i++)
        {
            if((1<<i)&dd)
            {
                x=anc[x][i];
            }
        } 
    }
    if(x!=y)
    {
        for(int i=28;i>=0;i--)
        {
            if(anc[x][i]!=anc[y][i])
            {
                x=anc[x][i];
                y=anc[y][i];
            }
        }
    }
    if(x==y) return x;
    else return anc[x][0];
}

bool use[size];
queue<int> q;

void spfa(int s)
{
    memset(dist,63,sizeof(dist));
    dist[s]=0;
    use[s]=1;
    q.push(s);
    while(q.size())
    {
        int f=q.front(); q.pop();
        use[f]=0;
        for(int i=head[f];i;i=nxt[i])
        {
            int v=l[i].t;
            if(dist[v]>dist[f]+l[i].d)
            {
                dist[v]=dist[f]+l[i].d;
                if(!use[v])
                {
                    use[v]=1;
                    q.push(v);
                }
            }
        }
    }
}

int main()
{
    int n,m,q;
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        build(a,b,c);
        build(b,a,c);
    }
    if(n<=2000)
    {
        while(q--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            spfa(x);
            printf("%d\n",dist[y]);     
        }
        return 0;
    }
    if(m==n-1)
    {
        dfs(1,0);
        while(q--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            int lca=asklca(x,y);
            printf("%d\n",dist[x]-dist[lca]+dist[y]-dist[lca]);
        }
        return 0;
    }
    else if(m==n)
    {

    }
    else
    {

    }
    return 0;
}

感觉没错但交上去WA一个点的代码……有点迷,不懂,求神犇打脸QAQ

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int size=100010;
int head[size],nxt[size],anc[size][30],deep[size],dist[size];
int tot=0;

struct edge{
    int t,d;
}l[size];
int n,m,q;

void build(int f,int t,int d)
{
    l[++tot]=(edge){t,d};
    nxt[tot]=head[f];
    head[f]=tot;
}

void dfs(int u,int fa)
{
    if(deep[u]>0) return ;
    deep[u]=deep[fa]+1;
    anc[u][0]=fa;
    for(int i=1;anc[anc[u][i-1]][i-1];i++)
    {
        anc[u][i]=anc[anc[u][i-1]][i-1];
    }
    for(int i=head[u];i;i=nxt[i])
    {
        int v=l[i].t;
        if(deep[v]==0) dist[v]=dist[u]+l[i].d;
        dfs(v,u);
    }
}

int asklca(int x,int y)
{
    if(deep[x]<deep[y]) swap(x,y);
    if(deep[x]>deep[y])
    {
        int dd=deep[x]-deep[y];
        for(int i=0;i<=24;i++)
        {
            if(dd&(1<<i))
            {
                x=anc[x][i];
            }
        }
    }
    if(x!=y)
    {
        for(int i=24;i>=0;i--)
        {
            if(anc[x][i]!=anc[y][i])
            {
                x=anc[x][i];
                y=anc[y][i];
            }
        }       
    }
    if(x==y) return x;
    else return anc[x][0];
}


int ask(int x,int y)
{
    int lca=asklca(x,y);
    return dist[x]-dist[lca]+dist[y]-dist[lca];
}


int main()
{
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n-1;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        build(a,b,c);
        build(b,a,c);
    }
    dfs(1,0);
    if(m==n-1)
    {
        while(q--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%d\n",ask(x,y));
        }
    }
    else if(m==n)
    {
        int x1,y1,d1;
        scanf("%d%d%d",&x1,&y1,&d1);
        while(q--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%d\n",min(ask(x,y),min( ask(x,x1)+d1+ask(y1,y) ,ask(x,y1)+d1+ask(x1,y) ) ) );
        }
    }
    else 
    {
        int x1,y1,d1,x2,y2,d2;
        scanf("%d%d%d",&x1,&y1,&d1);    
        scanf("%d%d%d",&x2,&y2,&d2);    
        while(q--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            int ans1=min( min( ask(x,x1)+d1+ask(y1,y) ,ask(x,y1)+d1+ask(x1,y) ) , min( ask(x,x2)+d2+ask(y2,y) , ask(x,y2)+d2+ask(x2,y) ) );
            int ans2=min( min( ask(x,x1)+d1+ask(y1,x2)+d2+ask(y2,y) , ask(x,x1)+d1+ask(y1,y2)+d2+ask(x2,y) ) , min( ask(x,x2)+d2+ask(y2,x1)+d1+ask(y1,y) , ask(x,x2)+d2+ask(y2,y1)+d1+ask(x1,y) ) );
            int ans3=min( min( ask(x,y1)+d1+ask(x1,x2)+d2+ask(y2,y) , ask(x,y1)+d1+ask(x1,y2)+d2+ask(x2,y) ) , min( ask(x,y2)+d2+ask(x2,x1)+d1+ask(y1,y) , ask(x,y2)+d2+ask(x2,y1)+d1+ask(x1,y) ) );
            int ans4=ask(x,y);
            printf("%d\n",min(min(ans1,ans2),min(ans3,ans4)));
        }
    }
    return 0;   
}
/*
x1-----y1  x2-----y2

x1 y1 x2 y2   x1 y1 y2 x2
y1 x1 x2 y2   y1 x1 y2 x2

x2 y2 x1 y1   x2 y2 y1 x1
y2 x2 x1 y1   y2 x2 y1 x1

*/

T3:破坏

对偶图?什么鬼

我打的迭代深搜,期望得分0~40,结果数据给的暴力分还可以,于是拿了40

正解(以下来自codevs官方题解):

首先看第一个点,显然我们要做到把所有未破坏的点都破坏掉,排序+去重求出有t个不重复的格子已经被破坏,则答案是m-t。
再看第二个点,显然只要任一个格子已经被破坏就可以了。如果k不为0则答案就是0,否则答案就是1。
然后看3,4,5三个点,可以暴力搜索每个格子是否破坏,然后暴力判断是否符合。综合以上能得到25分。
对于6,7,8三个点,可以用一些比较好的暴力然后剪一剪枝。
对于9~20十二个点:
首先有一个很重要的结论:未破坏的格子最上面与最下面不四连通,等价于,已破坏的格子最左面与最右面八连通。(似乎是对偶图性质?)接下来提到的联通和一步都是指八方向的。
我们要添加一些点使得左侧和右侧能联通,对于n,m<=1000的9~14六个点我们想到宽搜,所有原先已被破坏的联通块视为等价点,从左侧开始,每一步的代价是1,宽搜到右侧,等价点就是指当宽搜到某个已被破坏的点时,将所有等价点也就是该格子所在的联通块的全部格子全部赋为等值。
对于n,m很大但是k<=1000的15~20六个点就要有别的方法。考虑两个格子(x1,y1),(x2,y2),要将它们联通,代价应该是max{|x1-x2|-1,|y1-y2|-1,0}。要把(x,y)(第x行第y列)和左侧联通,代价为y-1。要把它和右侧联通,代价为m-y。这样做一遍从左侧到右侧的最短路即可,复杂度为O(k^2)。
本题要结合两种算法和两个小判断来做。

题解好像把9~14和15~20搞反了,不过无所谓233

正解条了半天没调出来……还是太弱,40分代码(跟没调出来的程序对拍发现好像有错…):

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<cstdlib>
using namespace std;
const int size=1010;
const int dx[]={0,-1,0,1,0};
const int dy[]={0,0,1,0,-1};
int maps[size][size];
int n,m,k;
int deep;
struct xy{
    int x,y;
};

queue<xy> q;
bool vis[size][size];
bool bfs(int x,int y)
{
    while(q.size()) q.pop();
    memset(vis,0,sizeof(vis));
    q.push((xy){x,y});
    vis[x][y]=1;
    while(q.size())
    {
        xy f=q.front(); q.pop();
        if(f.x==n) return false;
        for(int i=1;i<=4;i++)
        {
            int nx=f.x+dx[i];
            int ny=f.y+dy[i];
            if(nx>0&&nx<=n&&ny>0&&ny<=m&&!vis[nx][ny]&&!maps[nx][ny])
            {
                vis[nx][ny]=1;
                q.push((xy){nx,ny});
            }
        }
    } 
    return true;
}

void dfs(int x,int y,int d)
{
    if(d>deep) return ;
    if(d==deep)
    {
        int t=0;
        for(int i=1;i<=m;i++)
        if(bfs(1,i))  t++;
        if(t==m)
        {
        /*  for(int xx=1;xx<=n;xx++)
            {
                for(int yy=1;yy<=m;yy++)
                {
                    cout<<maps[xx][yy]<<" ";
                }
                puts("");
            }*/ 
            printf("%d\n",deep);
            exit(0);
        }
        return ;
    }
    if(x==n+1) return ;

    for(int i=x;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        if(!maps[i][j])
        {
            if(i==x&&j<y) continue;
            maps[i][j]=1;
            if(j==m) dfs(i+1,1,d+1);
            else dfs(i,j+1,d+1);
            maps[i][j]=0;
        }
    }
}


map<int,bool> h;
int main()
{   
    scanf("%d%d%d",&n,&m,&k);
    {
        if(k==0)
        {
            printf("%d",m);
            return 0;
        }
        if(n==1)
        {
            int tot=0;
            for(int i=1;i<=k;i++)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                if(!h[y]) {tot++;h[y]=1;}
            }
            printf("%d\n",m-tot);
            return 0;
        }
        else if(m==1)
        {
            if(!k) puts("1");
            else puts("0");
            return 0;
        }
    }
    for(int i=1;i<=k;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        maps[x][y]=1;
    }
    for(deep=0;deep<=m;deep++)
    {
        dfs(1,1,0);
    }
    return 0;
}

正解先挖坑,以后再填

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值