大概就是在有障碍的网格图里分别问能填充多少 C 和 F 形状的图形。严谨地叙述太复杂了,这里就不多叙述,直接去看 洛谷题面 吧。
然后顺便吐槽一下,这不愧是经典的 NOIP T1,感觉和上次的报数差不多,难度有点低了,比 CSP 的 T1 T2 都要简单,可惜考试取消了没考上。
做完之后翻了一下讨论区,似乎还有一些高妙的悬线法之类的解法,可以很简短地切掉这题。不过我不会我感觉不是很好像,所以这里提供一个思维难度极低,代码略长的做法,比较无脑,但是是妥妥的
大概就是手画一下找性质,然后发现,对于 C 型来说,当我们固定其上下两行之后,若最左侧列从上至下都是 C 的左侧的竖直的部分,然后把上下两侧可以延伸的乘起来加到方案里。
然后这东西是
然后我们发现这东西实际上是可以优化的,也就是说当我们确定一个竖直部分上端点所在行为
这样的话我们就随便做一个竖直方向上的前缀和即可优化 C 型的就过了。
对于维护最长能延申的距离,随便写一个 deque 即可,也就是双端队列,里面存下标,对于每个值如果为
然后考虑 F 型,这个需要想一下,发现对于一个确定的 C 型,变成 F 型就是乘上其下端点能够延伸的距离。这个正常做还是
Tips:有一些循环能压在一起,会让代码可读性变差这里就不压了。然后因为是 VP 也没打对拍,交上去最后两个点 WA 了,随便写了个满的数据才发现是最后加法没有取模。。。不过这种错误随便拍一下就能调出来,然后这题本身也很好调,思路非常直观,一步一步检查即可。
105123
45678910
11using namespace std;12
13mt19937 rnd(random_device{}());14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}15bool rnddd(int x){return rndd(1, 100) <= x;}16
17typedef unsigned int uint;18typedef unsigned long long unll;19typedef long long ll;20typedef long double ld;21
2223
24template < typename T = int >25inline T read(void);26
27int N, M, C, F;28bool mp[1100][1100];29int cline[1100][1100];30int srow[1100][1100];31int crow[1100][1100];32int line_x_row[1100][1100];33ll srowF[1100][1100];34ll cntC(0), cntF(0);35
36int main(){37 int T = read(); (void)read();38 while(T--){39 memset(mp, 0, sizeof mp);40 memset(cline, 0, sizeof cline);41 memset(srow, 0, sizeof srow);42 memset(crow, 0, sizeof crow);43 memset(line_x_row, 0, sizeof line_x_row);44 memset(srowF, 0, sizeof srowF);45 cntC = cntF = 0;46 N = read(), M = read(), C = read(), F = read();47 for(int i = 1; i <= N; ++i)48 for(int j = 1; j <= M; ++j){49 char c = getchar();50 while(c != '1' && c != '0')c = getchar();51 mp[i][j] = c - '0';52 }53 for(int i = 1; i <= N; ++i){//i = line, j - row54 deque < int > cur;55 for(int j = 1; j <= M; ++j)56 if(!mp[i][j])cur.emplace_back(j);57 else while(!cur.empty())cline[i][cur.front()] = cur.size() - 1, cur.pop_front();58 while(!cur.empty())cline[i][cur.front()] = cur.size() - 1, cur.pop_front();59 }60 // for(int i = 1; i <= N; ++i)for(int j = 1; j <= M; ++j)printf("%d%c", cline[i][j], j == M ? '\n' : ' ');61 for(int i = 1; i <= M; ++i){//i - row, j - line62 deque < int > cur;63 for(int j = 1; j <= N; ++j)64 if(!mp[j][i])cur.emplace_back(j);65 else while(!cur.empty())crow[i][cur.front()] = cur.size() - 1, cur.pop_front();66 while(!cur.empty())crow[i][cur.front()] = cur.size() - 1, cur.pop_front();67 }68 // for(int i = 1; i <= N; ++i)for(int j = 1; j <= M; ++j)printf("%d%c", crow[j][i], j == M ? '\n' : ' ');69 for(int i = 1; i <= M; ++i)//i - row, j - line70 for(int j = 1; j <= N; ++j)71 srow[i][j] = srow[i][j - 1] + cline[j][i];72 for(int i = 1; i <= M; ++i)73 for(int j = 1; j <= N; ++j)74 line_x_row[i][j] = crow[i][j] * cline[j][i] % MOD;75 for(int i = 1; i <= M; ++i)76 for(int j = 1; j <= N; ++j)77 srowF[i][j] = (srowF[i][j - 1] + line_x_row[i][j]) % MOD;78 for(int i = 1; i <= M; ++i)79 for(int j = 1; j <= N - 2; ++j){80 if(crow[i][j] < 2)continue;81 (cntC += (ll)cline[j][i] * (srow[i][j + crow[i][j]] - srow[i][j + 1]) % MOD) %= MOD;82 if(!crow[i][j + 2])continue;83 (cntF += (ll)cline[j][i] * (srowF[i][j + crow[i][j]] - srowF[i][j + 1]) % MOD) %= MOD;84 }85 printf("%lld %lld\n", cntC * C, cntF * F);86 }87 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);88 return 0;89}90
91template < typename T >92inline T read(void){93 T ret(0);94 int flag(1);95 char c = getchar();96 while(c != '-' && !isdigit(c))c = getchar();97 if(c == '-')flag = -1, c = getchar();98 while(isdigit(c)){99 ret *= 10;100 ret += int(c - '0');101 c = getchar();102 }103 ret *= flag;104 return ret;105}update-2022_11_28 初稿