前言
190分
100+0+60+30
明明是dfs专题
不太理想qwq
写了三个dfs就离谱
最不满意的是T2的爆零
其实分类讨论一下是很可做的
而且暴力还因为没开ll挂掉了…
不过毕竟构造题之前几乎没有做过
所以慢慢来吧
收获
一些构造题的trick
- 调整法
- 数学归纳法
- 分类讨论法
- 从边界极值等处缩小问题规模法
乱七八糟法
考场
先看题
数学的石头门困境重新江湖…
似乎就没有啥可做的题
在zld写在前面的难度指引+先写T1的习惯下
先看T1
(到现在似乎说是先看题结果几乎还是顺序做…)
zld果然没有骗我!
想到了把一个2*2的正方形作为基本单位单独处理
每块的最差处理次数也可以证明不超过4次
这样就ok了
但当时就想到这题代码实现可能会有些困难
应该又是道打表搬砖题
但奇怪的道路那题的阴间打表我都写过去了我还怕这个?
所以piapia就开始敲
这题我利用递归转移
自己感觉写的还是非常优美的
只需要一个操作对应的两个表和常规的4宫格tx数组即可
但我因为怕写挂自己造数据和手算输出用了好一段…
9:00
转T2
这什么玩意…
我也有些被zld的难度提示吓到了
觉得这题很可能需要按位考虑贪心的乱七八糟的
然后就越想越迷糊
最后直接开始开心的dfs
试图拿30分走人(伏笔)
9:30
开T3
又是让人没什么想法的题目
有一点直觉本题似乎很可能不会无解
(因为没有多测)
但推来推去也证明不出来
但是第二个30不超过2个讨厌的约束条件倒是推出来必定可行的策略了
然后就写了两个部分分拿60走人
10:10
看T4
又是不知从何推起的神仙题目
搞了半天除了浪费了一堆验算纸一无所获
最后又是dfs了…
复盘
T1
啊这个灯泡我觉得我点的是针不戳
很简洁
所以贴一下码awa
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=105;
const int mod=1e9+7;
int n,m;
int a[N][N];
int tot;
typedef pair<int,int>pr;
pr q[N*N<<2][4];
#define mkp make_pair
int dx[5][5]={{},{0,0,1,1},{0,0,1,1},{0,-1,-1,0},{0,-1,-1,0}};
int dy[5][5]={{},{0,1,0,1},{0,-1,-1,0},{0,0,1,1},{0,-1,0,-1}};
void work(int x,int y,int o){
// printf("work:x=%d y=%d o=%d\n",x,y,o);
tot++;
for(int i=1;i<=3;i++){
// printf(" xx=%d yy=%d\n",x+dx[o][i],y+dy[o][i]);
q[tot][i]=mkp(x+dx[o][i],y+dy[o][i]);
a[x+dx[o][i]][y+dy[o][i]]^=1;
}
}
int tx[5]={0,0,0,1,1},ty[5]={0,0,1,0,1};
void solve(int x,int y){
int cnt=a[x][y]+a[x+1][y]+a[x][y+1]+a[x+1][y+1];
// printf("x=%d y=%d cnt=%d\n",x,y,cnt);
if(cnt==0) return;
else if(cnt==1){
for(int i=1;i<=4;i++){
int nx=x+tx[i],ny=y+ty[i];
if(!a[nx][ny]){
work(x+tx[i],y+ty[i],i);
solve(x,y);
return;
}
}
}
else if(cnt==2){
for(int i=1;i<=4;i++){
int nx=x+tx[i],ny=y+ty[i];
if(a[nx][ny]){
// printf("nx=%d ny=%d\n",nx,ny);
work(nx,ny,i);
solve(x,y);
return;
}
}
}
else if(cnt==3){
for(int i=1;i<=4;i++){
int nx=x+tx[i],ny=y+ty[i];
if(!a[nx][ny]){
work(nx,ny,i);
solve(x,y);
return;
}
}
}
else{
work(x,y,1);
solve(x,y);
return;
}
}
int main(){
freopen("bulb.in","r",stdin);
freopen("bulb.out","w",stdout);
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
tot=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++) scanf("%1d",&a[i][j]);
}
if(n%2&&m%2){
if(a[n][m]) work(n-1,m-1,1);
}
if(m%2){
for(int i=1;i<n;i+=2){
if(a[i][m]&&a[i+1][m]) work(i,m-1,1);
else if(a[i][m]) work(i+1,m,4);
else if(a[i+1][m]) work(i,m,2);
}
}
if(n%2){
for(int j=1;j<m;j+=2){
if(a[n][j]&&a[n][j+1]) work(n-1,j,1);
else if(a[n][j]) work(n,j+1,4);
else if(a[n][j+1]) work(n,j,3);
}
}
for(int i=1;i<=n;i+=2){
for(int j=1;j<=m;j+=2) solve(i,j);
}
printf("%d\n",tot);
for(int i=1;i<=tot;i++){
for(int j=1;j<=3;j++) printf("%d %d ",q[i][j].first,q[i][j].second);
printf("\n");
}
}
return 0;
}
/*
5
2 2
10
11
3 3
011
101
110
4 4
1111
0110
0110
1111
5 5
01011
11001
00010
11011
10000
2 3
011
101
1
4 5
11011
11100
00000
01111
*/
T2
本题的关键性质是
只要从一个偶数往上连续取4个它的异或和就是0了
从一个偶数往上连续数2个就是1
所以分类讨论即可
但k=3和r=l+1且l为奇数的细节有点恶心
感觉可能考场上就是把这个性质想到了想切也没那么容易qwq
T3
调整法
可以证明随着不断调整组内的讨厌关系组数会越来越少
这样就能够证明一直处理下去一定能找到合法解了
T4
数学归纳法
这个东西就是看出来就看出来了…
当时感觉可能会用数学归纳法
但是归纳了半天归纳不出来…
把奇数消掉后变成2n-1的想法是关键
总结
构造毕竟是新题
做的比较少
关键是对关键性质的把握
明天放假了
好耶!