学习总结-12138

写在前

这周是摆烂的一周。。。

题目总结

P1332 血色先锋队
直接从瘟疫源头广搜,如果点没搜过就标记一下进队,如果搜过并且瘟疫到此点的时间大于这次到此点的时间进队。


#include <bits/stdc++.h>
#define eps 1e-15
using namespace std;
int a[505][505],visit[505][505],nx[4]={-1,1,0,0},ny[4]={0,0,-1,1};
int main()
{
    int n,m,n1,n2,t1,t2;
    queue<pair<int,int>> qans,q;
    pair<int,int> t;
	cin>>n>>m>>n1>>n2;
    for(int i=1; i<=n1; i++){
        cin>>t1>>t2;
        t=make_pair(t1,t2);
        q.push(t);
        visit[t1][t2]=1;
    }
    for(int i=1; i<=n2; i++){
        cin>>t1>>t2;
        t=make_pair(t1,t2);
        qans.push(t);
    }
    while(!q.empty()){
        t=q.front();
        q.pop();
        t1=t.first;t2=t.second;
        //cout<<t1<<" "<<t2;
        for(int k=0; k<4; k++){
            int xx = t1+nx[k],yy = t2+ny[k];
            if(xx>=1&&xx<=n&&yy>=1&&yy<=m){
                if(visit[xx][yy] == 0)a[xx][yy]=a[t1][t2]+1,t=make_pair(xx,yy),q.push(t),visit[xx][yy]=1;
                //剪枝
                else if(visit[xx][yy] == 1 && a[xx][yy] > a[t1][t2]+1)a[xx][yy]=a[t1][t2]+1,t=make_pair(xx,yy),q.push(t);
            }
        }
    }
    for(int i=1; i<=n2; i++){
        t=qans.front();
        qans.pop();
        cout<<a[t.first][t.second]<<endl;
    }
    return 0;
}

CF510B Fox And Two Dots
一开始想的是搜索每个点,最终看能否搜回开始的点,时间复杂度较高。
每次深搜标记下当前的坐标,在后续如果能搜回当前点就说明能形成一个圈。

#include <bits/stdc++.h>
#define eps 1e-15
using namespace std;
int nx[4]={-1,1,0,0},ny[4]={0,0,-1,1},visit[55][55],f,n,m;
char a[55][55];
void dfs(int x,int y,int x1,int y1){
    if(visit[x1][y1]){
        f=1;
        return;
    }
    visit[x1][y1]=1;
    for(int k=0; k<4; k++){
        int xx=x1+nx[k],yy=y1+ny[k];
        if(xx==x&&yy==y)continue;
        if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&a[x][y]==a[xx][yy])dfs(x1,y1,xx,yy);
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++)
        cin>>a[i][j];
    for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++)
    {   if(!visit[i][j])dfs(i,j,i,j);
        if(f==1){cout<<"Yes";return 0;}
    }
    cout<<"No";
    return 0;
}

P1665 正方形计数
直接爆搜o(n^4),数据最大500,超时。。。

#include <bits/stdc++.h>
#define eps 1e-8
#define PI 3.1415926
using namespace std;
/*
       不要被困在一种思路中
*/
int n,ans;
pair<double,double> p[505],x[4];
double getdis(pair<double,double> p1,pair<double,double> p2){
    return sqrt(pow(p1.first-p2.first,2)+pow(p1.second-p2.second,2));
}
bool judge(pair<double,double> p1,pair<double,double> p2,pair<double,double> p3,pair<double,double> p4){
//正方形只会有两种长度的边
    double l[6],a,b;
    l[0]=getdis(p1,p2);
    l[1]=getdis(p1,p3);
    l[2]=getdis(p1,p4);
    l[3]=getdis(p2,p3);
    l[4]=getdis(p2,p4);
    l[5]=getdis(p3,p4);
    a=l[0];
    for(int i=1; i<6; i++){
        if(l[i]==a)continue;
        else {b=l[i];break;}
    }
    for(int i=0; i<6; i++)
        if(l[i]!=a && l[i]!=b )return false;
    return true;
}
bool dfs(int i,int s){
    if(i==4){
        bool f=judge(x[0],x[1],x[2],x[3]);
        if(f)ans++;
        return f;
    }
    for(int j=s; j<=n; j++){
        x[i]=p[j];
        //玄学剪枝
        if(dfs(i+1,j+1) && i==3)break;
    }
    return false;
}
int main()
{
    cin>>n;
    for(int i=1; i<=n; i++)cin>>p[i].first>>p[i].second;
    dfs(0,1);
    cout<<ans;
    return 0;
}

正确的思路应该是枚举每两个点作为对角点,根据对角线算出另外两个点,看是否存在。o(n^3),可以用数组或map降到o(n ^2)

#include <bits/stdc++.h>
#define eps 1e-8
#define PI 3.1415926
using namespace std;
/*
       不要被困在一种思路中
*/
int n,ans;
pair<double,double> p[505];
bool judge(pair<double,double> p1,pair<double,double> p2){
//看图即可知,多出的两个直角三角形全等,可据此算出另外两个点
    double midx = (p1.first + p2.first) / 2;
    double midy = (p1.second + p2.second) / 2;
    double x1 = midx - (p1.second - midy), y1 = midy - (midx - p1.first);
    double x2 = midx + (p1.second - midy), y2 = midy + (midx - p1.first);
    int num=0;
    for(int i=1; i<=n; i++){
        if((p[i].first==x1&&p[i].second==y1) || (p[i].first==x2&&p[i].second==y2))num++;
    }
    if(num==2)return true;
    else return false;
}
int main()
{
    cin>>n;
    for(int i=1; i<=n; i++)cin>>p[i].first>>p[i].second;
    for(int i=1; i<=n; i++)
        for(int j=i+1; j<=n; j++)
        if(judge(p[i],p[j])){ans++;
/*            cout<<p[i].first<<" "<<p[i].second<<endl;
            cout<<p[j].first<<" "<<p[j].second<<endl;*/
        }
    cout<<ans/2;
    return 0;
}

D. Colorful Stamp
对这种类型的题理解的比较慢,以后需要加强一下。
只需要在每次遇到W时看一下前面R和B的数量,只要都不为0即可。

#include <bits/stdc++.h>
#define eps 1e-15
using namespace std;
string a;
bool check(int i,int j){
    int numr=0,numb=0;
    for(;i<=j; i++){
        if(a[i]=='R')numr++;
        else if(a[i]=='B')numb++;
    }
    return numr&&numb;
}
void solve(){
    int n;
    bool f=true;
    cin>>n;cin>>a;
    int i,j;
    for(i=0; i<a.length(); i++){
        if(a[i]=='W')continue;
        j=i+1;
        while(j<a.length()&&a[j]!='W')j++;
        if(!check(i,j)){
            f=false;
            break;
        };
        i=j;
    }
    if(f)cout<<"YES\n";
    else cout<<"NO\n";
}
int main()
{
    int t;
    cin>>t;
    while(t--)solve();

    return 0;
}

H. Maximal AND
简单的贪心,记录一下位运算的使用。
dalao博客
dalao博客

位操作符介绍
&按位与,操作数此位全为1结果为1,否则为0
|按位或,操作数此位有一个1结果为1,没有1为0
^按位异或,操作数此位不相同为1,相同为0
<<按位左移,高位舍去,低位补零
>>按位右移,高位补零,低位舍去
~按位取反,与原来此位相反
对于&运算可以用来判断第i位是0是1,例如:
a&(1<<i),将1左移i位,如果结果是原数,则是1。这个用法也可以用来判断是奇数还是偶数,例如a&1,如果是原数,则是奇数。
对于运算可以用来为2进制数特定的位赋值
例如0000000001变成00001,用代码就是0
<<左移1位相当于数据*2,>>右移1位相当于数据/2
#include <bits/stdc++.h>
#define eps 1e-15
using namespace std;
int n,k,a[35],p[35],ans;
void solve(){
    for(int i=30; i>=0; i--){
        if(a[i]+k>=n)k-=n-a[i],ans+=p[i];
    }
}
int main()
{
    int t;cin>>t;
    for(int i=0; i<=30; i++)
        p[i]=pow(2,i);
    while(t--){
        int tt;
        cin>>n>>k;
        memset(a,0,sizeof(a));
        ans=0;
        for(int i=1; i<=n; i++){
            cin>>tt;
            for(int j=30; j>=0; j--)if(tt-p[j]>=0)a[j]++,tt-=p[j];
        }
    solve();
    cout<<ans<<endl;
    }

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值