最近放学回家,咸鱼了一段日子,现在滚出来写题了。
B. 出题人的女装
这活生生一个高中数学题,但是我竟然WA了12次,看来数学水平退步了。
首先第一件衣服是女装,那么有可能是在第一个箱子选的,也有可能是第二个箱子选的,第一个箱子选女装的概率是x/n,第二个箱子选女装的概率是y/m,那么箱子是第一个的概率就是x/n / (x/n+y/m),是第二个的概率就是y/m /(x/n+y/m),然后就是水题啦。
#include
#define db double
#define ll long long
using namespace std;
ll gcd(ll x,ll y)
{
if(!y)return x;
return gcd(y,x%y);
}
int main()
{
ll n,m,x,y,t;
cin>>n>>m>>x>>y>>t;
ll zi=y*(y-1)*(n-1)*n+(x-1)*x*m*(m-1);
ll mu=(n-1)*(m-1)*(x*m+y*n);
ll yin=gcd(mu,zi);
zi/=yin,mu/=yin;
if(t==1)
printf("%lld/%lld\n",zi,mu);
if(t==0)
{
db ans=db(zi)/mu;
ans=ans*1000+0.5;
int tmp=(int)ans;
if(ans>=1000)puts("1.000");
else
{
if(ans<10)printf("0.00");
else if(ans<100)printf("0.0");
else printf("0.");
printf("%d\n",tmp);
}
}
}
C. 出题人的矩阵
比赛迟到了半个多小时,也在赛后刚好30分钟1A了这个题.....
我们分析一下,3*3的矩阵填写1到9这些数字,是不是一共有9!也就是362880种填法?那么我可以用dfs把所有合法的矩阵找出来,然后把这些合法矩阵当做多个起点跑最短路,每个矩阵对应每个点,开个数组记录9!个矩阵的最短路值,然后就可以直接输出答案咯。
#include
#define db double
#define ll long long
using namespace std;
const int maxn=4e5;
int a[4][4],b[4][4],vis[10],f[maxn],d[maxn],tot;
int check()
{
int ans=0;
for(int i=1;i<4;i++)
ans+=a[1][i];
for(int i=1;i<4;i++)
{
if(ans!=a[i][1]+a[i][2]+a[i][3])return 0;
if(ans!=a[1][i]+a[2][i]+a[3][i])return 0;
}
if(ans!=a[1][1]+a[2][2]+a[3][3])return 0;
if(ans!=a[3][1]+a[2][2]+a[1][3])return 0;
return 1;
}
int id(int t[4][4])//把每个矩阵都换成对应的点
{
int res=0;
for(int i=1;i<4;i++)
for(int j=1;j<4;j++)
res=res*10+t[i][j];
return lower_bound(f+1,f+1+tot,res)-f;//矩阵换成数在有序数组的下标是对应的点
}
struct node
{
int c[4][4];
node(int t[4][4])
{
for(int i=1;i<4;i++)
for(int j=1;j<4;j++)
c[i][j]=t[i][j];
}
};
queueq;
void bfs()//求多源最短路
{
while(!q.empty())
{
node e=q.front();q.pop();
int cur=id(e.c);
int dis=d[cur];
for(int i=1;i<4;i++)
for(int j=1;j<4;j++)
b[i][j]=e.c[i][j];
for(int i=1;i<=3;i++)
{
swap(b[1][i],b[2][i]);
int t=id(b);
if(d[t]>d[cur]+1)
d[t]=d[cur]+1,q.push(node(b));
swap(b[1][i],b[2][i]);
swap(b[3][i],b[2][i]);
t=id(b);
if(d[t]>d[cur]+1)
d[t]=d[cur]+1,q.push(node(b));
swap(b[3][i],b[2][i]);
swap(b[i][1],b[i][2]);
t=id(b);
if(d[t]>d[cur]+1)
d[t]=d[cur]+1,q.push(node(b));
swap(b[i][1],b[i][2]);
swap(b[i][3],b[i][2]);
t=id(b);
if(d[t]>d[cur]+1)
d[t]=d[cur]+1,q.push(node(b));
swap(b[i][3],b[i][2]);
}
}
}
void dfs(int x,int y)
{
if(x==4)
{
if(check())
{
int cur=id(a);
d[cur]=0;
q.push(node(a));
}
return;
}
for(int i=1;i<10;i++)
if(!vis[i])
{
a[x][y]=i;
vis[i]=1;
if(y!=3)dfs(x,y+1);
else dfs(x+1,1);
vis[i]=0;
}
}
void dfs2(int x,int v)//找到1到9的所有排列,每个矩阵对应每个排列
{
if(x==10)
{
f[++tot]=v;
return;
}
for(int i=1;i<=9;i++)
if(!vis[i])
{
vis[i]=1;
dfs2(x+1,v*10+i);
vis[i]=0;
}
}
int main()
{
for(int i=0;i
D. 出题人的手环
这个题其实很水,假设有数据1 3 2 4,首先我用树状数组求出原始的逆序数为p=1,假设我把4删除,假设t1为数组中比4大的数,t2为数组中比4小的数,那么删除后数组逆序数是p-t1,然后我在第一个位置插入一个4,新的逆序数就是p-t1+t2,没错,就这样借树状数组递推求出所有情况的逆序数就可以了,复杂度n*logn
#include
#define ll long long
#define low(x) x&-x
using namespace std;
const int maxn=2e5+10,mod=1e9+7;
int a[maxn],b[maxn],c[maxn],d[maxn],n;
int qu(int x)
{
int res=0;
while(x<=n)
res+=c[x],x+=low(x);
return res;
}
void up(int x)
{
while(x)
c[x]++,x-=low(x);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),b[i]=a[i];
sort(b+1,b+1+n);
for(int i=1;i<=n;i++)
{
a[i]=lower_bound(b+1,b+1+n,a[i])-b;
d[a[i]]++;
}
ll ans=0;
for(int i=1;i<=n;i++)
{
ans+=qu(a[i]+1);
up(a[i]);
}
ans%=mod;
ll p=ans;
for(int i=n;i>1;i--)
{
int t1=qu(a[i]+1);
int t2=n-d[a[i]]-t1;
p=(p+t2-t1+mod)%mod;
ans=ans*p%mod;
}
cout<