2021AutoX安途杯中山大学程序设计校赛 B Lights and Robot(思维)
Solution
这里有一个结论 (据说是找规律能找出来) :
假设打开了 cntr 行和 cntc 列的灯,那么所有亮灯的总数为
n ∗ c n t r + n ∗ c n t c − 2 ∗ c n t r ∗ c n t c n*cntr+n*cntc-2*cntr*cntc n∗cntr+n∗cntc−2∗cntr∗cntc
有了这个结论,我们就可以处理不进行对角线开关的所有操作。
对于对角线的操作,我们可以维护对角线上的所有亮灯的数量和对角线状态,
状态为 1 时(对角线操作数为奇数)输出时减去亮灯数再加上没亮的即可,
状态为 0 时(对角线操作数为偶数)直接输出结果。
代码
#include <algorithm>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
#define int long long
#define lowbit(x) ((x) & (-x))
using namespace std;
typedef pair<int, int> pii;
typedef pair<long, long> pll;
typedef pair<double, int> pdi;
typedef double dd;
typedef long long ll;
const int MAXN = 100010;
const int MAXM = 3000010;
const dd eps = 1e-6;
const int inf = 0x3f3f3f3f;
const ll llinf = 0x3f3f3f3f3f3f3f3f;
int n;
int r[MAXN], c[MAXN];
signed main()
{
int t;
scanf("%lld", &t);
while(t--)
{
memset(r, 0, sizeof(r)), memset(c, 0, sizeof(c));
int cntr = 0, cntc = 0, cntd = 0, ok = 0;
int n, m;
scanf("%lld%lld", &n, &m);
while(m--)
{
char ch[3];
scanf("%s", ch);
if(ch[0] == 'R')
{
int x;
scanf("%lld", &x);
r[x] ^= 1;
if(r[x])
cntr++;
else
cntr--;
if (r[x] ^ c[x])
cntd++;
else
cntd--;
}
else if(ch[0] == 'C')
{
int x;
scanf("%lld", &x);
c[x] ^= 1;
if(c[x])
cntc++;
else
cntc--;
if (r[x] ^ c[x])
cntd++;
else
cntd--;
}
else if(ch[0] == 'D')
{
ok ^= 1;
}
int ans = n * cntr + n * cntc - 2 * cntr * cntc;
if(!ok)
{
printf("%lld\n", ans);
}
else
{
printf("%lld\n", ans + n - 2 * cntd);
}
}
}
}
总结
(这谁找得到这个公式啊) 比赛时以为这是道区间操作的题。。有那么一瞬间想到是否存在结论,但是由于太菜没能推导出来。。