10月集训test16

本来应该昨天写的,结果Debug一直到今天。。。
100+20+0
第一题终于不负所望的AC了,第二题代码不够精致,本来应该可以拿50分的暴力,第三题少打了一个+1,少了40分的暴力。
上题。

1.cleaner

不是很难的题,本来代码没有自己写的那么复杂,只需要判一下是否到边界就可以了,结果我直接把边界拿出来另外算。
标准的算子矩阵和,用了容斥原理。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<cctype>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
using namespace std;

int d,n,x,y,c,tot,ans;
int a[1030][1030],b[1060900];

inline int read()
{
    int i=0;char c;
    for(c=getchar();c<'0'||c>'9';c=getchar());
    for(;c>='0'&&c<='9';c=getchar())
        i=(i<<1)+(i<<3)+c-'0';
    return i;
}

int main()
{
    //freopen("cleaner.in","r",stdin);
    //freopen("cleaner.out","w",stdout);

    d=read();n=read();
    for(int i=1;i<=n;i++)
    {
        x=read(),y=read(),c=read();
        a[x][y]=c;
    }
    for(int i=0;i<=1024;i++)
        for(int j=1;j<=1024;j++)
            a[i][j]+=a[i][j-1];
    for(int i=1;i<=1024;i++)
        for(int j=0;j<=1024;j++)
            a[i][j]+=a[i-1][j];

    for(int j=d+1;j<=1024-d;j++)
        b[++tot]=a[d*2][j+d]-a[d*2][j-d-1];
    for(int i=d+1;i<=1024-d;i++)
        b[++tot]=a[i+d][d*2]-a[i-d-1][d*2];
    for(int i=d+1;i<=1024-d;i++)
        b[++tot]=a[i+d][1024]-a[i-d-1][1024]-a[i+d][1024-d*2-1]+a[i-d-1][1024-d*2-1];
    for(int j=d+1;j<=1024-d;j++)
        b[++tot]=a[1024][j+d]-a[1024][j-d-1]-a[1024-d*2-1][j+d]+a[1024-d*2-1][j-d-1];
    b[++tot]=a[d*2][d*2];b[++tot]=a[d*2][1024]-a[d*2][1024-d*2-1];
    b[++tot]=a[1024][d*2]-a[1024-d*2-1][d*2];b[++tot]=a[1024][1024]-a[1024][1024-d*2-1]-a[1024-d*2-1][1024]+a[1024-d*2-1][1024-d*2-1];
    for(int i=d+1;i<=1024-d;i++)
        for(int j=d+1;j<=1024-d;j++)
            b[++tot]=a[i+d][j+d]-a[i-d-1][j+d]-a[i+d][j-d-1]+a[i-d-1][j-d-1];
    sort(b+1,b+tot+1);
    ans=1;      
    for(int i=tot-1;i>=1;i--)
        if(b[i]==b[tot])
            ans++;
        else
            break;
    printf("%d %d",ans,b[tot]);     
    return 0;   
}

2.friend

对就是这道题让我debug了很久很久很久。。。。。。
标准的最短路。
但是由于到后面边可能会有很多,加边会导致不可控的后果,所以不加边。将边权看成每走一步减1,直到0为止。dis[i][j][k]表示在(i,j)这个点且还有k的能量所花的最小费用。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<vector>
#define ll long long
using namespace std;

inline int read()
{
    int i=0,f=1;char c;
    for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
    if(c=='-')
        f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar())
        i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}

const int N=205;
const int fx[5]={0,-1,0,1,0};
const int fy[5]={1,0,-1,0,0};
const ll INF=0x3f3f3f3f3f3f3f3f;
int n,m,H,X[4],Y[4];
int a[N][N],b[N][N];
ll dis[N][N][N<<1],D[4][4];
struct node
{
    int d,x,y,h;
    friend inline bool operator >(const node &a,const node &b)
    {
        return a.d>b.d;
    }
};
priority_queue<node,vector<node>,greater<node> >q;

inline void zql(int S,int T1,int T2)
{
    int x,y,d,h;
    bool bz1=false,bz2=false;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            for(int k=0;k<=H;k++)
                dis[i][j][k]=INF;
    while(!q.empty()) q.pop();
    x=X[S],y=Y[S];
    dis[x][y][a[x][y]]=b[x][y];
    q.push((node){b[x][y],x,y,a[x][y]});
    while(!q.empty())
    {
        x=q.top().x,y=q.top().y,d=q.top().d,h=q.top().h;
        q.pop();
        if(x==X[T1]&&y==Y[T1]&&!h)
            D[S][T1]=d,bz1=true;
        if(x==X[T2]&&y==Y[T2]&&!h)
            D[S][T2]=d,bz2=true;
        if(bz1&&bz2) return;
        if(h>0)
        {
            for(int i=0;i<5;i++)
            {
                int dx=x+fx[i],dy=y+fy[i];
                if(dx<1||dx>n||dy<1||dy>m) continue;
                if(dis[dx][dy][h-1]>d)
                {
                    dis[dx][dy][h-1]=d;
                    q.push((node){d,dx,dy,h-1});
                }
            }
        }
        else
        {
            h=a[x][y];
            if(dis[x][y][h]>d+b[x][y])
            {
                dis[x][y][h]=d+b[x][y];
                q.push((node){dis[x][y][h],x,y,h});
            }
        }
    }
}

int main()
{
    n=read(),m=read();
    H=n+m-2;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            a[i][j]=min(read(),H);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            b[i][j]=read();
    X[1]=read(),Y[1]=read();
    X[2]=read(),Y[2]=read();
    X[3]=read(),Y[3]=read();
    for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++)
            D[i][j]=INF;
    zql(1,2,3);
    zql(2,1,3);
    zql(3,1,2);
    ll ans=INF;char p;
    if(D[2][1]+D[3][1]<ans)ans=D[2][1]+D[3][1],p='X';
    if(D[1][2]+D[3][2]<ans)ans=D[1][2]+D[3][2],p='Y';
    if(D[1][3]+D[2][3]<ans)ans=D[1][3]+D[2][3],p='Z';
    if(ans==INF)
        cout<<"NO";
    else 
        cout<<p<<endl<<ans;
    return 0;
}

3.ribbon

没有认真看样例说明啊,不是自己想的那样。
e.g.

覆盖0~5:
本以为 |0|1|2|3|4|5|
实际 0 1 2 3 4 5
    | | | | | |

所以暴力直接打挂了。。。。。
唔正解的话,并查集是一个好选择,从最后一次涂色开始,若后面涂色时该区域已被覆盖,就与该区域连到一起,用并查集维护。
这里写图片描述

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;

struct node
{
    int l,r;
}c[4000010];
int n,ans,rr;
int x[4000010],r[4000010];
bool a[4000010],flag[4000010];

inline int read()
{
    int i=0,f=1;char c;
    for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar()) ;
    if(c=='-') f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar()) 
        i=(i<<1)+(i<<3)+c-'0';
    return i*f;
}

inline int zql(int x)
{
    if(!a[x]||x==r[x])
        return x;
    r[x]=zql(r[x]);
    return r[x];
}

int main()
{
    //freopen("ribbon.in","r",stdin);
    //freopen("ribbon.out","w",stdout);

    n=read();
    for(int i=1;i<=n;i++)
    {
        c[n-i+1].l=read()+1;c[n-i+1].r=read();
        x[i*2-1]=c[n-i+1].l;x[i*2]=c[n-i+1].r;
    }
    int tot=n*2;
    for(int i=1;i<=n;i++)
        x[++tot]=c[i].r+1;
    sort(x+1,x+tot+1);
    tot=unique(x+1,x+tot+1)-x;
    for(int i=1;i<=n;i++)
    {
        c[i].l=lower_bound(x+1,x+tot+1,c[i].l)-x;
        c[i].r=lower_bound(x+1,x+tot+1,c[i].r)-x;
        rr=max(rr,c[i].r);
    }
    for(int i=1;i<=rr;i++)
        r[i]=i+1;
    for(int i=1;i<=n;i++)
        for(int j=c[i].l;j<=c[i].r;j++)
            if(!a[j])
            {
                a[j]=true;
                r[j-1]=j+1;
                if(!flag[i])
                    flag[i]=true,ans++;
            }
            else
            {
                r[j]=zql(r[j]);
                j=r[j];
                j--;
            }
    cout<<ans<<endl;
    return 0;
}

以上。
来自2017.10.31.(Halloween)

——我认为return 0,是一个时代的终结。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值