1004——MZL's game
当时全场没有队伍通过的一道题,此题状态构造的甚是巧妙
题意:n个人,每次从存活的人中等概率选出一个人去攻击场上其他人,被攻击者存活的概率相等 且由题目给出,选出的人出局。求一个人被攻击k次之后出局(被选出来攻击其他人后出局,受到攻击死亡不算出局)的概率。
思路:出题人的想法是先把这个问题转化为 从1,2...n顺次选取参与者去攻击其他人,如果被选者死亡,则直接选取下一个人即可。我们先处理出1,2...n的人受到 j 次攻击后存活的概率,dp[i][j]表示选取第 i 个人时,i 到 n的人都受到了 j 次攻击的概率,可以得到dp[i][j] = dp[i-1][j-1]*p1(第i-1个人受到j-1次攻击后存活的概率)+dp[i-1][j]*p2(第i-1个人在 j 次攻击内死亡的概率)。因为如果第 i-1 个人存活,那么必然会对i,i+1...n的人都进行一次攻击;只有当第i-1个人在之前的攻击中死亡,其余人才不会受到攻击。
一个人被攻击k次之后出局的概率其实就是dp[1,2...n][k]的和乘以p3(一个人受到k次攻击不死亡的概率)再除以n取平均数。在这里可以将dp[i][j]看作是第i个人受到j次攻击的概率。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long
#define MOD 258280327
LL power(LL x,LL k){
LL res=1;
while(k){
if(k&1)res=res*x%MOD;
x=x*x%MOD;
k>>=1;
}
return res;
}
LL dp[2100][2100];
int main(){
LL n,x,y,T;scanf("%lld",&T);
while(T--){
scanf("%lld%lld%lld",&n,&x,&y);
LL dead=x*power(y,MOD-2)%MOD;//dead probability of an attack
LL live=(MOD+1-dead)%MOD;//live probability of an attack
dp[1][0]=1;
for(int j=1;j<n;j++)dp[1][j]=0;
for(int i=2;i<=n;i++){// i th peolivee
dp[i][0]=0;
LL tmp=1;
for(int j=1;j<i;j++){// j times attacked
//move = i th live (live^(j-1)) + i th dead (1-live^(j))
dp[i][j]=dp[i-1][j-1]*tmp%MOD+dp[i-1][j]*(MOD+1-tmp*live%MOD)%MOD;
tmp=tmp*live%MOD;
}
}
for(int k=0;k<n;k++){
LL tmp=1;
LL ans=0;
for(int i=1;i<=n;i++){
if(i-1<k)tmp=tmp*live%MOD;
ans=(ans+dp[i][k])%MOD;
}
// ans*live^(k)/n
ans=ans*tmp%MOD*power(n,MOD-2)%MOD;
printf("%lld%c",ans,k==n-1?'\n':' ');
}
}
return 0;
}
1005——MZL's endless loop
题意:一个具有n个结点,m条无向边的无向图,要求我们规定每条边的方向,使其成为有向图之后每个结点的入度与出度差的绝对值小于1,若无解,则输出-1
解题思路:该题的解法有很多种,有用欧拉路的,也有用搜索的,而我要讲的方法就是深搜
首先我们先看看多校题解报告中的思路
出题人的想法是一张图中除了环就是树,根据左孝凌版离散数学中树的定义“无回路的连通图”可以得出这样一个结论,要么有回路(环),要么没有回路(树),无外乎这么两种情况,所以根据环与树各自的属性特点,此题从每个点开始DFS这张图就好了
下面给出我做此题时的思路
首先暂且先不考虑环还是树,直接进行深搜,对每个点进行出度和入度的判断,如果出度大,就先进行反向的搜索(每搜索一条边u,v就认为这是一条从v到u的有向边),如果入度大,进行正向搜索(每搜到一条边u,v认为这是一条从u到v的有向边),一直搜索到找不到边能继续为止。
注意:
①已经使用过的边为了防止再次被遍历到,可以修改head[u]的值,即head[u] = edge[i].next
②注意自环,因为能否继续向下层搜索是根据v的入度和出度大小来决定的,但是如果是自环的话可能会影响继续搜索。
另外,此题不存在无解的可能
反证法证明:假设存在一个结点v,满足该结点的入度比出度多2,那么,当有一条边搜索到v后找不到后继,导致v的入度比出度多1,这时又有一条边搜索到v,导致v的入度比出度多2,但是这样的话就会与第一条找不到后继的情况冲突,所以不会出现入度比出度多2的情况,其余情况亦是如此,所以不会有无解的结果。
代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 100005;
const int inf = 1000000000;
struct node
{
int to,next;
}edge[6*N];
int k,head[N],num[N],in[N],out[N],n,ans[N*3];
bool vis[N*6];
void add_edge(int from,int to)
{
edge[k].to=to;
edge[k].next=head[from];
head[from]=k++;
}
void DFS1(int u)
{
int i,v;
for(i=head[u];i+1;i=edge[i].next)
{
if(vis[i])
{
head[u]=edge[i].next;
continue;
}
v=edge[i].to;
if(u!=v&&in[v]>out[v])
continue;
out[u]++;
in[v]++;
vis[i]=vis[i^1]=true;
ans[i/2]=i%2?0:1;
head[u]=edge[i].next;
DFS1(v);
break;
}
}
void DFS2(int u)
{
int i,v;
for(i=head[u];i+1;i=edge[i].next)
{
if(vis[i])
{
head[u]=edge[i].next;
continue;
}
v=edge[i].to;
if(u!=v&&in[v]<out[v])
continue;
out[v]++;
in[u]++;
vis[i]=vis[i^1]=true;
ans[i/2]=i%2?1:0;
head[u]=edge[i].next;
DFS2(v);
break;
}
}
int main()
{
int t,m,i,u,v;
scanf("%d",&t);
while(t--)
{
k=0;
memset(head,-1,sizeof(head));
memset(num,0,sizeof(num));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(vis,false,sizeof(vis));
scanf("%d%d",&n,&m);
for(i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
num[u]++;
num[v]++;
}
for(i=1;i<=n;i++)
while(in[i]+out[i]<num[i])
if(in[i]>=out[i])
DFS1(i);
else
DFS2(i);
for(i=0;i<m;i++)
printf("%d\n",ans[i]);
}
return 0;
}
1006——MZL's simple problem
1 x : add number x to set
2 : delete the minimum number (if the set is empty now,then ignore it)
3 : query the maximum number (if the set is empty now,the answer is 0)
就是在set里进行简单操作。注意是to set,说的很明白了
代码:
#include<bits/stdc++.h>
using namespace std;
set<long long >::iterator it;
set<long long > s;
int main()
{
long long n, a, x;
scanf("%lld",&n);
s.clear();
while(n--)
{
scanf("%lld",&a);
if(a == 1)
{
scanf("%lld",&x);
s.insert(x);
}
else if(a == 2)
{
if(!s.empty())
s.erase(s.begin());
}
else if(a == 3)
{
if(s.empty())
puts("0");
else
{
it=s.end();
it--;
printf("%lld\n",*it);
}
}
}
return 0;
}
本文参考:
https://blog.csdn.net/queuelovestack/article/details/47303363