一些好的思维和搜索

写题一定要自己独立思考去写,如果当场做不出来,那么结束后一定要自己再手写,不可直接复制粘贴,自己独立去写才会发现问题

1后无0,0前无1,前缀和贪心 On优化On^2查找

怪怪的,数组范围2e5开到1e6加了memset才能过全部数据

const int N =1e6+10;
 
char a[N];
int b[N], c[N];
void solved()
{
       cin>>a+1;int n=strlen(a+1);
     
        memset(b,0,sizeof b);
        memset(c,0,sizeof c);
        for (int i = n - 1; i >= 1; i--)
        {
            if (a[i + 1]=='b')
                b[i] += b[i + 1] + 1;
            else
                b[i] += b[i + 1];
        }
         
        for (int i = 2; i <= n; i++)
        {
            if (a[i - 1]=='a')
                c[i] += c[i - 1] + 1;
            else
                c[i] += c[i - 1];
        }
     
        int mx = 2e9;
        for (int i = 1; i <= n; i++)
        {
                mx = min(b[i] + c[i], mx);
        }
        printf("%d\n",mx);
    }

dfs数一维数组连续1的个数

通过判断最后一位就好了

void dfs(int pos,int ans)
{
    if(pos>33){res=ans;return ;}
     
    if(q[pos]!=1&&q[pos-1]==1)dfs(pos+1,ans+1);
    if(res!=-1)return;
    dfs(pos+1,ans);
     if(res!=-1)return;  
}
void solved()
{
    memset(q,0,sizeof q);
    int n;cin>>n;
    for(int i=1;i<=n;i++)cin>>q[i];
     
    res=-1;
    int ans=0;
    //for(int i=1;i<=n+5;i++)if(q[i]!=1&&q[i-1]==1)ans++;
    dfs(1,0);
    printf("%d\n",res);
 
    ;
}

图论的dfs,void递归数组存答案

简单树的遍历,遇头节点直接过,不然更新当前答案

#include<bits/stdc++.h>
#define ll long long 
using namespace std;

const int N=1e5+10;
ll cnt[N],dis[N];
int w[N],c[N];
int h[N],ne[N<<1],e[N<<1],idx;
int n;

void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void dfs(int u,int fa,ll sum){
    dis[u]=sum;
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==fa)continue;
        ll t=cnt[c[j]];
        if(t>w[j])dfs(j,u,sum);
        else {
            cnt[c[j]]=w[j];
            dfs(j,u,sum-t+w[j]);
            cnt[c[j]]=t;
        }
    }
}
int main(){
    memset(h,-1, sizeof h);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>w[i];
    for(int i=1;i<=n;i++)cin>>c[i];
    for(int i=1;i<n;i++){
        int x,y;cin>>x>>y;
        add(x,y);
        add(y,x);
    }
    cnt[c[1]]=w[1];
    dfs(1,0,w[1]);
    for(int i=1;i<=n;i++) cout<<dis[i]<<endl;
    return 0;
}

传送门

acwing上:起点不定,范围在0到正无穷,给出一个传送求最短路,直接枚举左进传送门,右进传送门,跳过传送门取最小值

int main()
{
    cin>>a>>b>>x>>y;
    d1=abs(b-a);
    d2=abs(a-x)+abs(b-y);
    d3=abs(a-y)+abs(b-x);
    
    printf("%d",min({d1,d2,d3}));
    
    return 0;
}

牛客上:起点为0,不能跳过传送门,问是否会撞墙,直接存路径,直接从前往后走模拟,遇传送门则传送,否则++直走,看是否会碰壁

bool st[N];
unordered_map<int,int> mp;
void solved()
{
    int n,m,q;
    cin>>n>>m>>q;
    for(int i=0;i<m;i++)
    {
        int l,r;cin>>l>>r;
        mp[l]=r,mp[r]=l;
    }
    for(int i=0;i<q;i++)
    {
        int x;cin>>x;st[x]=1;
    }
     
    for(int pos=1;pos<=n;pos++)
    {
        if(mp[pos])pos=mp[pos];
        if(st[pos]){
            puts("NO");return;
        }
    }
    puts("YES");
     
    ;
}

翻牌

n张牌背面朝上,每次最多翻m张

一直WA,发现是没有考虑边界,m==0且n==0有解0,只m==0是无法翻牌无解

所以!!!一定要考虑同时为0,1,或者某种情况,简单题一般就是看这些细节

STL使用

竞赛比时间的话,边读入边操作更快

这里就可以边读入,边存map

void solved()
{
    int m,n;cin>>m>>n;
     
    if(m==0&&n==0)puts("0");
    else if(!n)puts("-1");
    else {
        int ans=m/n;
        if(m/n!=(double)m/n)ans++;
        printf("%d\n",ans);
    }
    ;
}

substr

substr(i,n);         i为string中的起点,n为截取长度

void solved()
{
    while(cin>>n)
    {
        int ans=0;
        string s;cin>>s;
        for(int i=0;i<n-3;i++)
        {
             
            if(s.substr(i,4)=="2020")ans++,i+=3;
        }
         
        print(ans);puts("");
    }
    ;
}

思维

如果满足序列为奇数,那么两两必有偶,即>=3无解

void solved()
{
    while(cin>>n>>m)
    {
        memset(g,0,sizeof g);
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                cin>>g[i][j];
         
        if(n==1)puts("Yes");
        else if(n>2)puts("No");
        else {
            int x=0;
            for(int i=0,j=0;i<m;i++)
                    x+=abs(g[j][i]-g[j+1][i]);
            puts(x&1?"Yes":"No");
             
        }
    }
    ;
}

判断大图里找字符串

找合适的子性质就好,这里是找2018中8的T

void solved()
{
    while(cin>>n>>m)
    {
        memset(g,0,sizeof g);
        for(int i=0;i<n;i++)cin>>g[i];
         
        bool ok=0;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++)
            {
                if(g[i][j]=='o'&&g[i-1][j]=='o'&&g[i+1][j]=='o'&&g[i][j+1]=='o')
                    ok=1;
                if(ok)break;
            }
            if(ok)break;
        }
         
        puts(ok?"2018":"2020");
    }
    ;
}

dfs按照性质搜索

大致题意,k次操作,每次只能走到边界或者撞上车子、障碍才停下

和扫对角线类似,xx,yy初始化i,j

while递归check性质

因为是dfs找答案所以回溯时要恢复现场

int m,n,k;
 
char g[N][N];
 
int dx[]={1,-1,0,0},dy[]={0,0,1,-1};
 
bool check(int x,int y)
{
    if(x<0||x>=n||y<0||y>=m||g[x][y]=='R'||g[x][y]=='X')return 0;
    return 1;
}
 
 bool ok=0;
 
void dfs(int u)
{
    if(ok)return;
    if(u>k)return;
     
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
        {
            if(g[i][j]=='R')
            {
                for(int p=0;p<4;p++)
                {
                    int xx=i,yy=j;
                    while(check(xx+dx[p],yy+dy[p]))xx+=dx[p],yy+=dy[p];
                    if(g[xx][yy]=='D')ok=1;
                    if(ok)return;
                     
                    swap(g[i][j],g[xx][yy]);
                    dfs(u+1);
                    swap(g[i][j],g[xx][yy]);
                }
            }
        }
}
void solved()
{
    cin>>m>>n>>k;
    for(int i=0;i<n;i++)cin>>g[i];
     
    
    ok=0;
    dfs(1);
    puts(ok?"YES":"NO");
    ;
}

暴搜dfs

直接暴力递归,每次递归完自动往下走,不考虑时间成本,注意剪枝。。

double get(double a,double b,double c)
{
    double p=(a+b+c)/2.0;
    return sqrt(p*(p-a)*(p-b)*(p-c));
}
 
bool check(int a,int b,int c)
{
    if(a+b>c&&a+c>b&&b+c>a)return 1;
     
    return 0;
}
 
int n;
double res=-1;
void dfs(int cnt,int a,int b,int c){
    if(cnt>n) return;
     if(check(a,b,c)){
         double sum=get(a,b,c);
         if(res<sum) res=sum;
     }
    dfs(cnt+1,a,b,c+q[cnt]);
    dfs(cnt+1,a+q[cnt],b,c);
    dfs(cnt+1,a,b+q[cnt],c);
    dfs(cnt+1,a,b,c);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值