文章目录
题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);
}
}
}