春季月考 #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;
}