题404.csp-2206 P1归一化处理&P2寻宝!大冒险!&P3角色授权&P4光线追踪


题404.csp-2206 P1归一化处理&P2寻宝!大冒险!&P3角色授权&P4光线追踪


一、P1归一化处理

1.题目:

在这里插入图片描述
在这里插入图片描述

2.题解:

本题套个公式做计算,注意参与计算的数的数据类型定义为double即可。
代码如下:

#include <bits/stdc++.h>

#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define pb push_back
#define x first
#define y second

using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int Inf=0x3f3f3f3f;
const int maxn=1100;

int n;
double a[maxn];

int main()
{
    cin>>n;
    double sum=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%lf",&a[i]);
        sum+=a[i];
    }
    double tmp=0;
    for(int i=1;i<=n;i++) tmp+=(a[i]-sum/n)*(a[i]-sum/n);
    for(int i=1;i<=n;i++)
    {
        double d=a[i]-sum/n;
        printf("%f\n",d/sqrt(tmp/n));
    }
}

二、P2寻宝!大冒险!

1.题目:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.题解:

本题就是要你统计出有几个合法原点,即宝藏埋藏地(必在树下)。我们会想着直接去暴力枚举每个树点作为原点,然后看藏宝图的其他点是否完全能够对应到绿化图上(条件1:不越界;条件2:树情况一致)。树点采用集合set来存储,方便后期判断树点情况。
代码如下:

#include <bits/stdc++.h>

#define x first
#define y second

using namespace std;

typedef pair<int,int> pii;

const int maxs=55;

int n,L,S;
set<pii> s;
int g[maxs][maxs];

int main()
{
    cin>>n>>L>>S;
    for(int i=0;i<n;i++)
    {
        int x,y;
        cin>>x>>y;
        s.insert({x,y});
    }
    for(int i=S;i>=0;i--)
    {
        for(int j=0;j<=S;j++) cin>>g[i][j];
    }
    int cnt=0;
    for(auto p:s)//枚举原点
    {
        int x=p.x,y=p.y;
        int flag=1;//合法标记
        for(int i=0;i<=S;i++)
        {
            for(int j=0;j<=S;j++)
            {
                int xx=x+i,yy=y+j;
                if(xx>L||yy>L)//越界判断
                {
                    flag=0;//越界非法
                    break;
                }
                //树情况判断
                if(g[i][j])//藏宝图(i,j)有树
                {
                    if(!s.count({xx,yy}))//则到绿化图上对应位置看是否有树,如果没有则非法
                    {
                        flag=0;
                        break;
                    }
                }
                else//藏宝图(i,j)无树
                {
                    if(s.count({xx,yy}))//则到绿化图上对应位置看是否有树,如果有则非法
                    {
                        flag=0;
                        break;
                    }
                }
            }
            if(!flag) break;
        }
        if(flag) cnt++;//合法则可行原点数++
    }
    cout<<cnt;
}

三、P3角色授权

1.题目:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.题解:

这题就读懂题意之后直接模拟,然后没优化前想的是角色信息里头操作、资源类型、资源名用unordered_set存然后查授权的时候用us.count()去查,结果交上去超时了70分。
代码如下:

//70分代码,运行超时
#include <bits/stdc++.h>

using namespace std;

struct RoleInfo
{
    string name;
    unordered_set<string> ops;
    unordered_set<string> stypes;
    unordered_set<string> snames;
};

int n,m,q;
unordered_map<string,RoleInfo> roles;
unordered_map<string,unordered_set<string>> rels;

void initRoleinfo()
{
    for(int i=0;i<n;i++)
    {
        string name;
        cin>>name;
        RoleInfo ri;
        ri.name=name;
        int nv;
        cin>>nv;
        for(int j=0;j<nv;j++)
        {
            string op;
            cin>>op;
            roles[name].ops.insert(op);
        }
        int no;
        cin>>no;
        for(int j=0;j<no;j++)
        {
            string stype;
            cin>>stype;
            roles[name].stypes.insert(stype);
        }
        int nn;
        cin>>nn;
        for(int j=0;j<nn;j++)
        {
            string sname;
            cin>>sname;
            roles[name].snames.insert(sname);
        }
    }
}

void initRoleRel()
{
    for(int i=0;i<m;i++)
    {
        string name;
        cin>>name;
        int ns;
        cin>>ns;
        for(int j=0;j<ns;j++)
        {
            string type,ug;
            cin>>type>>ug;
            rels[ug].insert(name);
        }
    }
}

bool checkRole(string name,string op,string stype,string sname)
{
    auto ri=roles[name];
    if(ri.ops.size()&&!ri.ops.count(op)&&!ri.ops.count("*")) return false;
    if(ri.stypes.size()&&!ri.stypes.count(stype)&&!ri.stypes.count("*")) return false;
    if(ri.snames.size()&&!ri.snames.count(sname)&&!ri.snames.count("*")) return false;
    return true;
}

void check()
{
    for(int i=0;i<q;i++)
    {
        int flag=0;
        string uname;
        cin>>uname;
        int ng;
        cin>>ng;
        vector<string> gs;
        for(int j=0;j<ng;j++)
        {
            string gname;
            cin>>gname;
            gs.push_back(gname);
        }
        string op,stype,sname;
        cin>>op>>stype>>sname;

        //查用户名本身
        if(rels.find(uname)!=rels.end())
        {
            for(auto role:rels[uname])
            {
                if(checkRole(role,op,stype,sname))
                {
                    flag=1;
                    break;
                }

            }
        }

        //查用户组
        for(auto gname:gs)
        {
            for(auto role:rels[gname])
            {
                if(checkRole(role,op,stype,sname))
                {
                    flag=1;
                    break;
                }
            }
        }
        if(flag) cout<<1<<endl;
        else cout<<0<<endl;
    }
}

int main()
{
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>n>>m>>q;
    initRoleinfo();
    initRoleRel();
    check();
}

tip:unordered_set中的元素没有按照任何特定的顺序排序,而是根据它们的散列值组织成桶,从而允许通过它们的值直接快速访问单个元素(平均时间复杂度为常数)。

之后就想着优化,然后就想着把作为string的那堆名字化成int的id,关系存成邻接矩阵,查关系直接查就好,结果一交满分了。。。
代码如下:

//满分代码,string名int后用邻接矩阵直接判关系优化
#include <bits/stdc++.h>

using namespace std;

const int maxn=550,maxm=234650;//卡了波内存极限

int n,m,q;
int G[maxn][maxm],cnt[maxn];
unordered_map<string,unordered_set<string>> rels;//记得用unordered_map
unordered_map<string,int> rid,oid;//将角色名、操作名、资源类型名、资源名化成id,用于后续直接用邻接矩阵判断角色和后三者是否有关系
int rcnt=0,ocnt=550;

void initRoleinfo()
{
    for(int i=0;i<n;i++)
    {
        int u,v;
        string name;
        cin>>name;
        u=rid[name]=++rcnt;
        int nv;
        cin>>nv;
        for(int j=0;j<nv;j++)
        {
            string op;
            cin>>op;
            if(oid.count(op)) v=oid[op];
            else v=oid[op]=++ocnt;
            G[u][v]=1;
        }
        int no;
        cin>>no;
        for(int j=0;j<no;j++)
        {
            string stype;
            cin>>stype;
            if(stype=="*")
            {
                stype="**";
            }
            if(oid.count(stype)) v=oid[stype];
            else v=oid[stype]=++ocnt;
            G[u][v]=1;
        }
        int nn;
        cin>>nn;
        for(int j=0;j<nn;j++)
        {
            string sname;
            cin>>sname;
            if(oid.count(sname)) v=oid[sname];
            else v=oid[sname]=++ocnt;
            G[u][v]=1;
            cnt[u]++;
        }
    }
}

void initRoleRel()
{
    for(int i=0;i<m;i++)
    {
        string name;
        cin>>name;
        int ns;
        cin>>ns;
        for(int j=0;j<ns;j++)
        {
            string type,ug;
            cin>>type>>ug;
            rels[ug].insert(name);
        }
    }
}

bool checkRole(string name,string op,string stype,string sname)
{
    int u=rid[name];
    int v,v0;
    v=oid[op],v0=oid["*"];
    if(!G[u][v]&&!G[u][v0]) return false;
    v=oid[stype],v0=oid["**"];
    if(!G[u][v]&&!G[u][v0]) return false;
    v=oid[sname];
    if(cnt[u]&&!G[u][v]) return false;
    return true;
}

void check()
{
    for(int i=0;i<q;i++)
    {
        int flag=0;
        string uname;
        cin>>uname;
        int ng;
        cin>>ng;
        vector<string> gs;
        for(int j=0;j<ng;j++)
        {
            string gname;
            cin>>gname;
            gs.push_back(gname);
        }
        string op,stype,sname;
        cin>>op>>stype>>sname;

        //查用户名本身
        if(rels.find(uname)!=rels.end())
        {
            for(auto role:rels[uname])
            {
                if(checkRole(role,op,stype,sname))
                {
                    flag=1;
                    break;
                }

            }
        }

        //查用户组
        for(auto gname:gs)
        {
            for(auto role:rels[gname])
            {
                if(checkRole(role,op,stype,sname))
                {
                    flag=1;
                    break;
                }
            }
        }
        if(flag) cout<<1<<endl;
        else cout<<0<<endl;
    }
}

int main()
{
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);//开始的时候没加这个,因为我没想到csp的题可以加这个能快多少的,没想到一加就不超时了
    cin>>n>>m>>q;
    initRoleinfo();
    initRoleRel();
    check();
}

四、P4光线追踪

1.题目:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.题解:

这题也是读懂题意之后直接模拟,对于3操作步骤可分为三步:联立光线方程与反射镜方程求最近反射点、修改反射之后光线方向、得到新光线方程,循环这个过程,直到I<1ort不够用了结束,最后码完一交,成功超时了。
代码如下:

//35分代码,运行超时
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const ll Inf=LONG_LONG_MAX;

struct Mirror
{
    double k;//斜率
    int type;//直线类型,增or减
    ll x1,y1,x2,y2;//两点
    double a;//系数
};

int m;
unordered_map<int,Mirror> mirrors;

void check(ll x0,ll y0,int d,double I,ll t)
{
    while(1)
    {
        ll nx,ny,mind=Inf;
        double a;
        int type;
        if(d==0||d==2)//x方向,光直线方程为y=y0;
        {
            //联立直线方程求最近交点
            for(auto mirror:mirrors)
            {
                auto info=mirror.second;
                ll x=info.k*(y0-info.y1)+info.x1;
                ll y=y0;
                if(x==x0) continue;
                if(d==0&&x<x0||d==2&&x>x0) continue;
                if(x<=min(info.x1,info.x2)||x>=max(info.x1,info.x2)||y<=min(info.y1,info.y2)||y>=max(info.y1,info.y2)) continue;
                ll dd=abs(x-x0);
                if(dd<mind)
                {
                    mind=dd;
                    nx=x,ny=y;
                    type=info.type;
                    a=info.a;
                }
            }
            //判断t内是否能走到反射镜
            if(mind<=t)
            {
                if(type==-1&&d==0||type==1&&d==2) d=3;
                else if(type==-1&&d==2||type==1&&d==0) d=1;
                x0=nx,y0=ny;
                I=a*I;
                if(I<1)
                {
                    cout<<"0 0 0"<<endl;
                    break;
                }
                t-=mind;
            }
            else
            {
                I=floor(I);
                if(I==0) cout<<"0 0 0"<<endl;
                else
                {
                    if(d==0) x0=x0+t,y0=y0;
                    else x0=x0-t,y0=y0;
                    cout<<x0<<" "<<y0<<" "<<(int)I<<endl;
                }
                break;
            }
        }
        else//y方向,光直线方程为x=x0
        {
            for(auto mirror:mirrors)
            {
                auto info=mirror.second;
                ll x=x0;
                ll y=(1/info.k)*(x0-info.x1)+info.y1;
                if(y==y0) continue;
                if(d==1&&y<y0||d==3&&y>y0) continue;
                if(x<=min(info.x1,info.x2)||x>=max(info.x1,info.x2)||y<=min(info.y1,info.y2)||y>=max(info.y1,info.y2)) continue;
                ll dd=abs(y-y0);
                if(dd<mind)
                {
                    mind=dd;
                    nx=x,ny=y;
                    type=info.type;
                    a=info.a;
                }
            }

            //判断t内是否能走到反射镜
            if(mind<=t)
            {
                if(type==-1&&d==1||type==1&&d==3) d=2;
                else if(type==-1&&d==3||type==1&&d==1) d=0;
                x0=nx,y0=ny;
                I=a*I;
                if(I<1)
                {
                    cout<<"0 0 0"<<endl;
                    break;
                }
                t-=mind;
            }
            else
            {
                I=floor(I);
                if(I==0) cout<<"0 0 0"<<endl;
                else
                {
                    if(d==1) x0=x0,y0=y0+t;
                    else x0=x0,y0=y0-t;
                    cout<<x0<<" "<<y0<<" "<<(int)I<<endl;
                }
                break;
            }
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>m;
    for(int i=1;i<=m;i++)
    {
        int op;
        cin>>op;
        if(op==1)
        {
            ll x1,y1,x2,y2;
            double a;
            cin>>x1>>y1>>x2>>y2>>a;
            Mirror mirror;
            mirror.k=(y2-y1)/(x2-x1);
            if(mirror.k>0) mirror.type=1;
            else mirror.type=-1;
            mirror.x1=x1,mirror.y1=y1,mirror.x2=x2,mirror.y2=y2;
            mirror.a=a;
            mirrors[i]=mirror;
        }
        else if(op==2)
        {
            int k;
            cin>>k;
            mirrors.erase(k);
        }
        else
        {
            ll x,y,t;
            double I;
            int d;
            cin>>x>>y>>d>>I>>t;
            check(x,y,d,I,t);
        }
    }
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值