当强制在线遇上卡常大赛~
题目乱七八糟的。事实上你按照他说的构造出a数组,然后交换。然后相连的两个点ab只有a在b的右下方或者b在a的右下方。要求字典序最大,显然我们可以每次贪心选择最大的,然后他左上的矩阵和右下的矩阵都不能选了。
那么30pts的暴力。我们可以每次选择一个最大的,然后暴力记录一下每一行被覆盖到了第几列,然后到一个点的时候直接看看这一行这一列有没有被覆盖,即能不能被选择。开了O2即可A掉此题
60pts的暴力。可以发现随机生成数据。那么每次选择的点可以发现,左上角右下角删掉的矩形一定很大,那么我们只需要在剩下的两个小矩形中暴力查找最大值,最后输出就行了
100嘛。。。每次从全局找一个最大的值, 我们可以暴力枚举每一行, 维护一个数据结构来查询最大值。
注意到这个数据结构要支持删掉一个前缀/后缀, 查询最大值,
我们可以直接在笛卡尔树上向左或向右递归即可。没写
笛卡尔树可以用单调栈建立,这里仅给出std
30pts 但是开了O2可以AC的代码
#include
#include
#include
#include
#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]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
#include
#include
#include
#include
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]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
#include
#include
#include
#include
#include
#include
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;
}
bfs30pts啦
然而zyb有一种优秀的暴力,从终点开始,跳的长度从1开始扫,把空白加入队列,每次队列再从零开始。。。这样很难被卡掉,暴力艹标算啊
然后zyb有一种科学的暴力。
优秀的暴力
#include
#include
#include
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
#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&&awhere,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&&areturn "Impossible";
}
inline void judge(){
freopen("bird.in","r",stdin);
freopen("bird.out","w",stdout);
}
int main(){
judge();
cout<return 0;
}
这个题目确实可以写O(m^2logn)的暴力,即枚举每一条边,表示他是要变成的数(变成这些边里面的数字一定更优嘛,中位数啊),然后把别的边的边权都变成|a-b|,然后最小生成树。。。
100pts嘛,仔细分析和最小方差生成树并没有什么差别,最小方差生成树参考今年的集训队论文,好像是有个结论来着orz
暴力略,正解不会。。。