C - Find it!
题意:给一个图,让我们找到一个环
思路:首先我们找到环上的一点,点的映射即可,然后我们从这个点进行找到他的环
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int t;
int tt;
void solve(){
int n;
cin>>n;
vector<int >g(n+1);
vector<int>ans;
for (int i = 1; i <=n ; ++i) {
cin>>g[i];
}
vector<bool>vis(n+1,false);
int k=0;
for (int i = 1; i <=n ; ++i) {
if(g[i]!=i){
for (int j = i; vis[j]==false ; j=g[j]) {
if(vis[g[j]]==true){
k=g[j];
break;
}
vis[j]=true;
}
break;
}
}
vector<int>st(n+1);
for (int i = k; g[i]!=k ; i=g[i]) {
ans.push_back(i);
}
ans.push_back(g[ans.back()]);
cout<<ans.size()<<endl;
for (auto i:ans) {
cout<<i <<' ';
}
}
signed main(){
t=1;
while (t--){
solve();
}
}
D - Grid Ice Floor
题意:一个n * m的图,我们从(2,2)出发,我们只能沿某个方向走,遇到墙壁才可以改变方向,问我们可以碰到的.的数量是多少
思路:BFS进行搜索,while循环遍历那个方向,当我们碰到墙时,返回一下,再把这个点加入队列,同时再进行搜索
代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define int long long
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
int n,m,ans;
bool st[510][510];
int mp[510][521];
char g[521][520];
signed main(){
// ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m;
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=m ; ++j) {
cin>>g[i][j];
}
}
queue<pair<int,int>>q;
q.push({2,2});
while (!q.empty()){
auto t =q.front();
int x=t.first,y=t.second;
q.pop();
st[x][y]=true;
mp[x][y]=1;
for (int i = 0; i <4 ; ++i) {
int xx=x,yy=y;
while (g[xx+dx[i]][yy+dy[i]]=='.'){
xx+=dx[i],yy+=dy[i];
mp[xx][yy]=1;
}
if(!st[xx][yy]) {
st[xx][yy] = true;
q.push({xx, yy});
}
}
}
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=m ; ++j) {
ans+=mp[i][j];
}
}
cout<<ans<<endl;;
}
E - Defect-free Squares
题意:给一个n m的网格,有k个点残缺的,问这个图中的正方形的个数是多少个,残缺的就不算了,1 1算一个
思路:残缺的标记为1,二维前缀和求一下,然后对每一个点进行枚举,我们二分一下以当前点为左上角的点,对它的边长进行二分,我们可以求出右下角的点,当我们发现如果长度为3时成立,那么这个点为顶点所能贡献的个数就是3
代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,ans;
int s[3005][3005];
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int k;
cin>>n>>m>>k;
while (k--){
int x,y;
cin>>x>>y;
s[x][y]++;
}
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=m ; ++j) {
s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
}
}
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=m ; ++j) {
int l=1,r=min(n-i+1,m-j+1);
// cout<<r<<endl;
int res=0;
while (l<=r){
int mid=l+r>>1;
int a=i+mid-1;
int b=j+mid-1;
if(s[a][b]-s[i-1][b]-s[a][j-1]+s[i-1][j-1]==0){
l=mid+1;
// cout<<mid;
res=mid;
}
else r=mid-1;
}
// cout<<res<<endl;
int a=i+res-1,b=j+res-1;
if(s[a][b]-s[i-1][b]-s[a][j-1]+s[i-1][j-1]==0)ans+=res;
}
}
cout<<ans<<'\n';
}
F - Yet Another Grid Task
题意:
- 给定一个初始二维网格,格子有黑有白。
- 如果一个格子(i,j)是黑的,那么(i+1,j)(i+1,j+1)也应该是黑的。
- 初始条件不一定满足上述条件,现在你可以对格子涂成黑色,问满足上述条件的局面数
思路:
首先我们初始化初始条件下的情况,将每个黑格子的右下方全涂成黑色,逐行遍历即可。
然后在这个基础上考虑如何计数,考虑按列枚举。
当我们一列一列考虑时,我们采取的决策是对这一列的哪一行涂成黑色。涂色的格子必须是白色,在考虑当前列时,我们需要的信息是当前列的格子的颜色,当这一行是黑色时,这一列的所有大于这一行都得是黑色。
即考虑,设f[i][j]表示前i列,第i列的情况是j行及以下都是黑色,以上都是白色的方案数,前一列的格子状态对当前列有影响。
对于当前的第i列,如果在初始满足条件的局面s中,第j行开始是黑色的话,那么所有f[i][k>=j]=0。
然后考虑dp[i][k<=j]的情况,第k个格子原本是白色,现在涂成黑色,情况有两种
-
自己涂成黑的,或者本身就是黑的,
-
由于前一列的影响,该列的该行是黑的
-
对于第一种$f[ i ][ j ] $=$ sum_{j = k}^{n + 1}dp[i - 1][j] $
- 第二种 $f[i][j]$ = $dp[i - 1][k - 1]$ 对于$sum_{}$这边我们可以进行一个后缀和的处理,这样转移就可以$O(1)$的转移了。
初始条件就是$f[0][n]$=1;
代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
//#define int long long
const int mod=998244353;
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int n,m;
cin>>n>>m;
vector<string>s(n+2);
for (int i = 0; i <n ; ++i) {
cin>>s[i];
}
for (int i = 0; i <n ; ++i) {
for (int j = 0; j <m ; ++j) {
if(s[i][j]=='#'){
if(i+1<n){
s[i+1][j]='#';
}
if(j+1<m&&i+1<n){
s[i+1][j+1]='#';
}
}
}
}
vector<int>f(n+1,0);
f[n]=1;
for (int i = 0; i < m; ++i) {
int sum=0;
vector<int>f2(n+1,0);
for (int j = n; j >=0 ; --j) {
sum=(sum+f[j])%mod;
if(j>0&&s[j-1][i]=='#')continue;
if(j>0){
f2[j]=(f[j-1]+sum)%mod;
}
else{
f2[j]=sum;
}
}
f.swap(f2);
}
int ans=0;
for (int i = 0; i <= n; ++i) {
ans=(ans+f[i])%mod;
}
cout<<ans<<endl;
}