传送门:点击打开链接
题意:有一个n*n的区域,左上角坐标为(0,0),在左上角有一个机器人,他每次留在原地和前往其他可前往的格子的概率相等,最后若干时间之后,求机器人最后在(x,y)(x+y>=n-1)的点的概率是多少。
分析: 给每个点赋一个权值,权值的大小就代表当前点可以被几个点所到达(包括自身),4个角落的点的权值为3,边缘除角落的权值为4,其余点权值为5,分母就是所有点的权值和,分子是所有终点的权值和。因为n=10000,所以不能暴力,但是因为障碍最多只有1000个,所以我们可以用map或者set把所有的障碍事先存起来。之后对于这些点枚举,用总贡献减去这些点的贡献即可。注意可以需要注意障碍点到达障碍点不需要减,我们需要set标记判断。注意n=1特判。
补充:C++中,结构体是无法进行==,>,<,>=,<=,!=,需要重载,=不需要重载,set内部元素会自动排序,所以set<结构体>需要重载<。
我的代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<set>
#include<map>
#include<stack>
#include<queue>
using namespace std;
const int N = 1e4+10;
#define ll long long
#define pb push_back
#define inf 0x3f3f3f3f
#define eps 1e-10
ll t,n,k,fz,fm;
int to[4][2]={-1,0,1,0,0,-1,0,1};
struct br{
ll x,y;
bool operator==(const br &a) {///重载==
return (x==a.x)&&(y==a.y);
}
bool operator < (const br a) const {///重载<
if(x==a.x) return y<a.y;
return x<a.x;
}
}b[N];
set<br> st;
ll gcd(ll a,ll b) {
if(b==0) return a;
else return gcd(b,a%b);
}
ll gv(ll x,ll y) {
ll s=5;
if(x==0||x==n-1) s--;
if(y==0||y==n-1) s--;
return s;
}
void sv() {
fz=9+8*(n-2)+5*(n-1)*(n-2)/2;
fm=12+16*(n-2)+5*(n-2)*(n-2);
for(int i=0;i<k;i++) {
fm-=gv(b[i].x,b[i].y);
if(b[i].x+b[i].y>=n-1) fz-=gv(b[i].x,b[i].y);
for(int j=0;j<4;j++) {
ll xx=b[i].x+to[j][0],yy=b[i].y+to[j][1];
if(xx<0||xx>=n||yy<0||yy>=n||st.count({xx,yy})) continue;
fm--;
if(xx+yy>=n-1) fz--;
}
}
ll tp=gcd(fz,fm);
fz/=tp,fm/=tp;
cout<<fz<<"/"<<fm<<endl;
st.clear();
}
int main() {
ios::sync_with_stdio(0);
cin>>t;
for(int l=1;l<=t;l++){
cin>>n>>k;
for(int i=0;i<k;i++) cin>>b[i].x>>b[i].y,st.insert({b[i].x,b[i].y});
cout<<"Case #"<<l<<": ";
if(n==1) {
if(k==1) cout<<"0"<<endl;
else cout<<"1"<<endl;
}else sv();
}
return 0;
}
参考代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int n,m,p,q;
map<pair<int,int>,int> ma;
int check(int x,int y) //判断当前点的贡献
{
if((x==0||x==n-1)&&(y==0||y==n-1)) return 3;
if((x==0||x==n-1)&&(y!=0&&y!=n-1)) return 4;
if((y==0||y==n-1)&&(x!=0&&x!=n-1)) return 4;
return 5;
}
int main()
{
int QAQ,kase=0;
scanf("%d",&QAQ);
while(QAQ--)
{
ma.clear();p=0,q=0;
scanf("%d%d",&n,&m);
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
ma[make_pair(x,y)]=1;
}
if(n==1) //n==1 特判
{
if(m==1) printf("0\n");
else printf("1");
}
else
{
q+=((3*4)+((n-2)*4*4)+(n-2)*(n-2)*5); //分母
p+=((3*3)+((n-2)*2*4)+((n-2)*(n-1)/2*5)); //分子
for(auto it=ma.begin();it!=ma.end();it++) //遍历所有障碍
{
int x=it->first.first;
int y=it->first.second;
q-=check(x,y); //减去对分母的贡献
if(x+y>=n-1) p-=check(x,y); //减去对分子的贡献
for(int i=0;i<4;i++) //判断对周围点的贡献的影响
{
int xx=x+dx[i];
int yy=y+dy[i];
if(xx>=0&&xx<n&&yy>=0&&yy<n&&ma.count(make_pair(xx,yy))==0)
{
if(xx+yy>=n-1) p--;
q--;
}
}
}
int gk=__gcd(p,q); //化简
printf("Case #%d: %d/%d\n",++kase,p/gk,q/gk);
}
}
system("pause");
}