春季月考 #3

A.Kill Quicksort

经典的卡快排题。

快排在数组正序/逆序是会到达最大的时间复杂度 \(O(n^2)\),但是这个代码里边是随机选择的。

我们发现他这个随机函数是定死的,而且种子已经告诉我们了。

于是我们将计就计:

  • 先把所有数组元素值赋 \(0\)
  • 模拟一遍快排
  • 把每一次查到的随机元素赋值为当前最大值

于是我们可以构造了:

#include <bits/stdc++.h>
using namespace std;

const unsigned mul = 20201011;
unsigned long long state;

unsigned long long retrieve() {
    unsigned modulo = 0x7fffffff;
    state = ((unsigned long long) state * mul) % modulo;
    unsigned high = state;
    state = ((unsigned long long) state * mul) % modulo;
    return high * modulo + state;
}

int retrieve(int a, int b) {
    return (int) (retrieve() % (b - a + 1)) + a;
}

int n,val[100010],p[100010],cnt;

int cmp(int x, int y){return val[x] - val[y];}

void quicksort(int l,int r)
{
    int t = retrieve(l, r);
    val[p[t]] = cnt--; //New
    int i = l, j = r, k = p[t];
    do{
        while (cmp(p[i], k)<0) i++;
        while (cmp(p[j], k)>0) j--;
        if (i <= j) swap(p[i], p[j]), i++, j--;
    }while (i <= j);
    if (i < r) quicksort(i, r);
    if (j > l) quicksort(l, j);
}

int main()
{
    scanf("%llu",&state);
    /* scanf("%d", &n); */
    puts("1000"); n = 1000; cnt = n; //New
    for (int i = 1; i <= n; i++)
        /* scanf("%d", &val[i]), p[i] = i; */
        val[i] = 0, p[i] = i; //New
    quicksort(1, n);
    for (int i = 1; i <= n; i++)
        printf("%d ", max(val[i],1));
    return 0;
}

神奇。

D. Entropy

首先,如果所有字符都是相同的,那么就是 \(0\),于是我们从全 \(0\) 开始改。

但这样对于熵大的字符串不友好,于是我们再从所有字符都 \(1\)​ 个开始随机改。

最后几个过不了的搞一搞就好了,面向数据。

E. Camping

老师给的外挂:他自己写的知乎

这里是第一种:

#include <bits/stdc++.h>
using namespace std;

int n,a[1010][1010];

int Query(int x,int y){
    if(a[x][y]){
        return a[x][y];
    }else{
        printf("? %d %d\n",x-1,y-1);fflush(stdout);
        int res;scanf("%d",&res);a[x][y]=res;
        return res;
    }
}

void Solve(int xl,int xr,int yl,int yr)
{
    if(xl==xr){
        printf("! %d %d\n",xr-1,yr-1);
        return;
    }else{
        if(xr-xl==1){
            int a=Query(xl,yl);
            int b=Query(xl,yl+1);
            int c=Query(xl+1,yl);
            int d=Query(xl+1,yl+1);
            if(a>b&&a>c) printf("! %d %d\n",xl-1,yl-1);return;
            if(b>a&&b>d) printf("! %d %d\n",xl-1,yl);  return;
            if(c>a&&c>d) printf("! %d %d\n",xl,yl-1);  return;
            if(d>b&&d>c) printf("! %d %d\n",xl,yl);    return;
        }else{
            int xm=(xl+xr)>>1;
            int ym=(yl+yr)>>1;
            int Max=0,Maxx=0,Maxy=0,A;
            for(int i=xl;i<=xr;i++) {A=Query(i,yl);if(A>Max)Max=A,Maxx=i,Maxy=yl;} //第一列
            for(int i=xl;i<=xr;i++) {A=Query(i,ym);if(A>Max)Max=A,Maxx=i,Maxy=ym;} //中间列
            for(int i=xl;i<=xr;i++) {A=Query(i,yr);if(A>Max)Max=A,Maxx=i,Maxy=yr;} //第三列
            for(int i=yl+1;i<yr;i++){A=Query(xl,i);if(A>Max)Max=A,Maxx=xl,Maxy=i;} //第一行
            for(int i=yl+1;i<yr;i++){A=Query(xr,i);if(A>Max)Max=A,Maxx=xr,Maxy=i;} //中间行
            for(int i=yl+1;i<yr;i++){A=Query(xm,i);if(A>Max)Max=A,Maxx=xm,Maxy=i;} //第三行

            int m=0,mx,my,flag=true;
            if(Maxx-1>=xl){A=Query(Maxx-1,Maxy);if(A>Max&&A>m)flag=false,m=A,mx=Maxx-1,my=Maxy;} //比上面小
            if(Maxx+1<=xr){A=Query(Maxx+1,Maxy);if(A>Max&&A>m)flag=false,m=A,mx=Maxx+1,my=Maxy;} //比下面小
            if(Maxy-1>=yl){A=Query(Maxx,Maxy-1);if(A>Max&&A>m)flag=false,m=A,mx=Maxx,my=Maxy-1;} //比左边小
            if(Maxy+1<=yr){A=Query(Maxx,Maxy+1);if(A>Max&&A>m)flag=false,m=A,mx=Maxx,my=Maxy+1;} //比右边小
            if(flag) {printf("! %d %d\n",Maxx-1,Maxy-1);return;} //如果最大

            if(mx<xm&&my<ym)       Solve(xl,xm-1,yl,ym-1); //找找左上
            else if (mx>xm&&my<ym) Solve(xm+1,xr,yl,ym-1); //找找左下
            else if (mx<xm&&my>ym) Solve(xl,xm-1,ym+1,yr); //找找右上
            else                   Solve(xm+1,xr,ym+1,yr); //找找右下
        }
    }
}

int main()
{
    scanf("%d",&n);
    Solve(1,n,1,n);
    fflush(stdout);
    return 0;
}
posted @ 2024-05-05 10:37  Sundar_2022  阅读(5)  评论(0编辑  收藏  举报