2018SD省队集训R1 D5

当强制在线遇上卡常大赛~

T1

题解:

题目乱七八糟的。事实上你按照他说的构造出a数组,然后交换。然后相连的两个点ab只有a在b的右下方或者b在a的右下方。要求字典序最大,显然我们可以每次贪心选择最大的,然后他左上的矩阵和右下的矩阵都不能选了。

那么30pts的暴力。我们可以每次选择一个最大的,然后暴力记录一下每一行被覆盖到了第几列,然后到一个点的时候直接看看这一行这一列有没有被覆盖,即能不能被选择。开了O2即可A掉此题

60pts的暴力。可以发现随机生成数据。那么每次选择的点可以发现,左上角右下角删掉的矩形一定很大,那么我们只需要在剩下的两个小矩形中暴力查找最大值,最后输出就行了

100嘛。。。每次从全局找一个最大的值, 我们可以暴力枚举每一行, 维护一个数据结构来查询最大值。
注意到这个数据结构要支持删掉一个前缀/后缀, 查询最大值,
我们可以直接在笛卡尔树上向左或向右递归即可。没写
笛卡尔树可以用单调栈建立,这里仅给出std

代码:

30pts 但是开了O2可以AC的代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long 
using namespace std;
const int N=5005;
double A[N][N];
int n,m,l[N],r[N];
struct hh{int x,y;double z;bool operator < (const hh&a) const {return z>a.z;};}S[N*N],ans[N*N];
int main()
{
    freopen("random.in","r",stdin);
    freopen("random.out","w",stdout);
    int k,x0,y0,x1,y1;scanf("%d%d%d",&n,&m,&k);
    for (int i=1;i<=n;i++)
    {
        LL a,b,c,d,a1,b1,c1,d1,t,t1;
        scanf("%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&t,&a1,&b1,&c1,&d1,&t1);
        A[i][0]=(double)t/(t1+1);
        for (int j=1;j<=m;j++)
        {
            t=(a*t*t+b*t+c)%d;
            t1=(a1*t1*t1+b1*t1+c1)%d1;
            A[i][j]=(double)t/(t1+1);
        }
    }
    for (int i=1;i<=k;i++) scanf("%d%d%d%d",&x0,&y0,&x1,&y1),swap(A[x0][y0],A[x1][y1]);
    int top=0;
    for (int i=1;i<=n;i++)
      for (int j=1;j<=m;j++)
        S[++top].x=i,S[top].y=j,S[top].z=A[i][j];
    sort(S+1,S+top+1);int ans0=0;
    for (int i=1;i<=n;i++) l[i]=0,r[i]=m+1;
    for (int i=1;i<=top;i++)
      if (l[S[i].x]<S[i].y && r[S[i].x]>S[i].y)
    {
        for (int j=1;j<=S[i].x;j++) l[j]=max(l[j],S[i].y);
        for (int j=S[i].x;j<=n;j++) r[j]=min(r[j],S[i].y);
        ans[++ans0].x=S[i].x,ans[ans0].y=S[i].y;
    }
    printf("%d\n",ans0);
    for (int i=1;i<=ans0;i++) printf("%d %d\n",ans[i].x,ans[i].y);
}

60pts 不是我的的代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define LL long long 
int n,m,k,top,ans[5005];
double A[5005][5005];
inline int P(int x,int y) {return (x-1)*m+y;}
inline void F(int a,int &x,int &y) {x=(a-1)/m+1,y=(a-1)%m+1;}
void solve(int l1,int r1,int l2,int r2)
{
    if (l1>r1||l2>r2) return;
    int xx=l1,yy=l2;
    for (int i=l1;i<=r1;i++)
     for (int j=l2;j<=r2;j++)
      if (A[xx][yy]<A[i][j]) xx=i,yy=j;
    solve(l1,xx-1,yy+1,r2);
    solve(xx+1,r1,l2,yy-1);
    ans[++top]=P(xx,yy);
}
bool cmp(int p,int q)
{
    int x,y,z,w; F(p,x,y); F(q,z,w); return A[x][y]>A[z][w];
}
int main()
{
    freopen("random.in","r",stdin);
    freopen("random.out","w",stdout);
    int k,x0,y0,x1,y1;scanf("%d%d%d",&n,&m,&k);
    for (int i=1;i<=n;i++)
    {
        LL a,b,c,d,a1,b1,c1,d1,t,t1;
        scanf("%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&t,&a1,&b1,&c1,&d1,&t1);
        A[i][0]=(double)t/(t1+1);
        for (int j=1;j<=m;j++)
        {
            t=(a*t*t+b*t+c)%d;
            t1=(a1*t1*t1+b1*t1+c1)%d1;
            A[i][j]=(double)t/(t1+1);
        }
    }
    for (int i=1;i<=k;i++) scanf("%d%d%d%d",&x0,&y0,&x1,&y1),swap(A[x0][y0],A[x1][y1]);
    solve(1,n,1,m); sort(ans+1,ans+top+1,cmp);
    printf("%d\n",top);
    for (int i=1;i<=top;i++) 
    {
        int x,y; F(ans[i],x,y);
        printf("%d %d\n",x,y);
    }
}

100pts 不是我的的std

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
using namespace std;
#define li long long
#define gc getchar()
#define pc putchar
li read(){
    li x = 0;
    int y = 0,c = gc;
    while(!isdigit(c)){
        y = c;
        c = gc;
    }
    while(isdigit(c)){
        x = (x << 1) + (x << 3) + (c ^ '0');
        c = gc;
    }
    return y == '-' ? -x : x;
}
void print(li q){
    if(q < 0){
        pc('-');
        q = -q;
    }
    if(q >= 10) print(q / 10);
    pc(q % 10 + '0');
}
int n,m,k;
#define ldb double
ldb v[5010][5010];
struct node{
    short x,y;
    bool operator < (const node &q) const{
        return v[x][y] < v[q.x][q.y];
    }
}w[13][5010][5010],tmp;
int cnt;
int ans[10010][2],tot;
int lgo[5010];
int l[5010],r[5010];
inline node getmx(int q){
    int z = l[q],x = r[q];
    if(z > x) return tmp;
    int p = lgo[x - z + 1];
    return w[p][q][z] < w[p][q][x - (1 << p) + 1] ? w[p][q][x - (1 << p) + 1] : w[p][q][z];
}
int main(){
    freopen("random.in","r",stdin);freopen("random.out","w",stdout);
    li a,b,c,d,e,f,g,h,p,q;
    register int i,j,o;
    n = read();m = read();k = read();
    for(i = 1;i <= n;++i){
        a = read();b = read();c = read();d = read();p = read();e = read();f = read();g = read();h = read();q = read();
        a %= d;b %= d;c %= d;p %= d;e %= h;f %= h;g %= h;q %= h;v[i][0] = p / (q + 1.0);
        for(j = 1;j <= m;++j){
            p = ((a * p + b) * p + c) % d;
            q = ((e * q + f) * q + g) % h;
            v[i][j] = p / (q + 1.0);
        }
    }
    for(i = 1;i <= k;++i){
        a = read();b = read();c = read();d = read();
        swap(v[a][b],v[c][d]);
    }
    for(i = 2;i <= m;++i) lgo[i] = lgo[i >> 1] + 1;
    for(i = 1;i <= n;++i) l[i] = 1,r[i] = m;
    for(i = 1;i <= n;++i){
        for(j = 1;j <= m;++j){
            w[0][i][j].x = i;w[0][i][j].y = j;
        }
    }
    for(i = 1;i <= 12;++i){
        for(j = 1;j <= n;++j){
            for(o = 1;o + (1 << i) - 1 <= m;++o) w[i][j][o] = w[i - 1][j][o] < w[i - 1][j][o + (1 << i - 1)] ? w[i - 1][j][o + (1 << i - 1)] : w[i - 1][j][o];
        }
    }
    while(1){
        node nw,tp;
        nw.x = nw.y = tp.x = tp.y = 0;
        for(i = 1;i <= n;++i){
            tp = getmx(i);
            if(nw < tp) nw = tp;
        }
        if(!nw.x && !nw.y) break;
        ans[++tot][0] = nw.x;ans[tot][1] = nw.y;
        for(i = nw.x - 1;i;--i) l[i] = max(l[i],nw.y + 1);
        for(i = nw.x + 1;i <= n;++i) r[i] = min(r[i],nw.y - 1);
        l[nw.x] = n + 1;r[nw.x] = -1;
    }
    print(tot);pc('\n');
    for(i = 1;i <= tot;++i){
        print(ans[i][0]);pc(' ');print(ans[i][1]);pc('\n');
    }
    return 0;
}

T2

题解:

bfs30pts啦

然而zyb有一种优秀的暴力,从终点开始,跳的长度从1开始扫,把空白加入队列,每次队列再从零开始。。。这样很难被卡掉,暴力艹标算啊

然后zyb有一种科学的暴力。

代码:

优秀的暴力

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N=2005;
bool vis[N][N];int a[N][N];
struct hh{int x,y;}q[N*N];
int c[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int main()
{
// freopen("bird.in","r",stdin);
//  freopen("bird.out","w",stdout);
    int n,m,k,stx,sty,enx,eny;scanf("%d%d%d",&n,&m,&k);
    scanf("%d%d%d%d",&stx,&sty,&enx,&eny);stx++; sty++; enx++; eny++;
    if (stx==enx && sty==eny) {printf("Possible\n");return 0;}
    for (int i=1;i<=n;i++)
      for (int j=1;j<=m;j++) scanf("%d",&a[i][j]);
    if (a[stx][sty]==1 || a[enx][eny]==1) {printf("Impossible");return 0;}

    int head=0,tail=0;
    vis[enx][eny]=1;q[++tail].x=enx; q[tail].y=eny;
    for (int j=1;j<=k;j++)
    {
        head=1;
        while (head<=tail)
        {
            hh now=q[head++];
            for (int i=0;i<4;i++)
            {
                int x=now.x+c[i][0]*j,y=now.y+c[i][1]*j;
                if (x<=0 || y<=0 || x>n || y>m || a[x][y] || vis[x][y]) continue;
                q[++tail].x=x; q[tail].y=y;vis[x][y]=1;
            }
        }
        if (vis[stx][sty]) {printf("Possible\n");return 0;}
    }
    printf("Impossible");
}

出题人科学的暴力

// BEGIN CUT HERE

// END CUT HERE
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define forE(i,x) for(int i=head[x];i!=-1;i=ne[i])
using namespace std;
typedef long long i64;
typedef unsigned long long u64;
typedef unsigned u32;
typedef pair<int,int> pin;
#define mk(a,b) make_pair(a,b)
#define lowbit(x) ((x)&(-(x)))
#define sqr(a) ((a)*(a))
#define clr(a) (memset((a),0,sizeof(a)))
#define ls(x) ((x)<<1)
#define rs(x) (((x)<<1)|1)
#define mid (((l)+(r))>>1)
#define pb push_back
#define w1 first
#define w2 second
inline void read(int &x){
    x=0;int f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    x*=f;
}

/*******************************head*******************************/
const int maxn=2005;
int grid[maxn][maxn];
struct info{
    int x,y,where;
}x[16000100];
int d[2100][2100][4],bo[2100][2100],head,now,mo=16000000;
const int dx[]={0,1,0,-1};
const int dy[]={1,0,-1,0};
inline void update(int X,int y,int where,int z){
    if(d[X][y][where]>z){
        d[X][y][where]=z;
        int w=d[x[now].x][x[now].y][x[now].where];
        if(z<=w){
            now--;if(now<0)now=mo;
            x[now]=(info){X,y,where};
        }else{
            head++;if(head>mo)head=0;
            x[head]=(info){X,y,where};
        }
    }
}
string solve() {
    int N,M,E;read(N);read(M);read(E);
    int r1,c1,r2,c2;
    read(r1);read(c1);read(r2);read(c2);
    rep(i,0,N-1)rep(j,0,M-1)read(grid[i][j]);
    cerr<<"ok"; 
    now=1;
    memset(d,0x3f,sizeof(d));
    rep(i,0,3)update(r2,c2,i,0);
    int tot=0;
    while(now!=head+1&&(head!=mo||now!=0)){
        info k=x[now];tot++;
        now++;if(now>mo)now=0;
        int k1=k.x,k2=k.y,where=k.where,k3=d[k1][k2][where];
        if(k1==r1&&k2==c1&&k3<=E)return "Possible";
        int a=k1+dx[where],b=k2+dy[where];
        if(a>=0&&b>=0&&a<N&&b<M)update(a,b,where,k3+1);
        if(grid[k1][k2]==0){
            rep(i,0,3){
                int a=k1+dx[i]*k3,b=k2+dy[i]*k3;
                if(a>=0&&b>=0&&a<N&&b<M)update(a,b,i,k3);
            }
        }
    }return "Impossible";
}
inline void judge(){
    freopen("bird.in","r",stdin);
    freopen("bird.out","w",stdout);
}
int main(){
    judge();
    cout<<solve();
    return 0;
}

T3

题解:

这个题目确实可以写O(m^2logn)的暴力,即枚举每一条边,表示他是要变成的数(变成这些边里面的数字一定更优嘛,中位数啊),然后把别的边的边权都变成|a-b|,然后最小生成树。。。

100pts嘛,仔细分析和最小方差生成树并没有什么差别,最小方差生成树参考今年的集训队论文,好像是有个结论来着orz

代码:

暴力略,正解不会。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值