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;

}
posted on 2023-07-24 10:30  IR101  阅读(16)  评论(0编辑  收藏  举报  来源