2019牛客多校训练(二)
比赛链接:
https://ac.nowcoder.com/acm/contest/882#question
A.Eddy Walker
题意:
在一个$n$个节点的环中,一个人随机向前或者向后,求出他刚好走过所有节点时,位于$m$点的概率
分析:
对于$n$等于18,我们可以用随机数模拟移动的方向,记录以$i$点结束的次数
发现,除了0点不可能结束,其它点结束的概率相同,那么概率就只能是$\frac{1}{n-1}$
ac代码:
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define pa pair<int,int>
using namespace std;
const int maxn=14+5;
const int maxm=1e7+10;
const ll mod=1e9+7;
ll qpow(ll x,ll y)
{
ll res=1,k=x;
while(y)
{
if(y%2)res=res*k%mod;
k=k*k%mod;
y/=2;
}
return res;
}
int main()
{
//cout<<qpow(2,10)<<endl;
int T,n,m;
scanf("%d",&T);
ll ans=1;
while(T--)
{
scanf("%d %d",&n,&m);
if(n==1&&m==0)
;
else if(n!=0&&m==0)
ans=0;
else
ans=ans*qpow((n-1),mod-2)%mod;
printf("%lld\n",ans);
}
return 0;
}
F.Partition problem
题意:
总共有$2n$个人,分成两队
如果a,b不在一队那么竞争值+$V_{ab}$
求最大竞争值
分析:
用dfs暴力搜索在$2n$人里面选择$n$个人的所有情况,注意每次加人和减人都去除或添加点的影响,而不要等在搜索到结果再执行这个操作
这样,复杂度从$C(2n,n)n^{2}$降到了$C(2n,n)n$,因为给了四秒,刚好可以跑过去
ac代码:
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define pa pair<int,int>
using namespace std;
const int maxn=14+5;
const int maxm=1e7+10;
const ll mod=998244353;
int num[maxn],ma[maxn*2][maxn*2],n;
ll v[maxn*2],ans;
bool vis[maxn*2];
void dfs(int s,int f)
{
if(s-f>n)return ;
if(vis[s])
{
vis[s]=false;
for(int j=1;j<=2*n;j++)v[j]-=ma[s][j];
}
num[f]=s;
if(f==n)
{
ll res=0;
for(int i=1;i<=n;i++)
res+=v[num[i]];
// for(int i=1;i<=2*n;i++)
// cout<<vis[i]<<" ";
// cout<<endl;
ans=max(ans,res);
// cout<<res<<endl;
return ;
}
for(int i=s+1;i<=2*n;i++)
{
dfs(i,f+1);
if(vis[i]==false)
{
vis[i]=1;
for(int j=1;j<=2*n;j++)v[j]+=ma[i][j];
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=2*n;i++)
for(int j=1;j<=2*n;j++)
scanf("%d",&ma[i][j]);
for(int i=1;i<=2*n;i++)vis[i]=true;
for(int i=1;i<=2*n;i++)for(int j=1;j<=2*n;j++)v[i]+=ma[i][j];
for(int i=1;i<=2*n;i++)
{
dfs(i,1);
if(vis[i]==false)
{
vis[i]=true;
for(int j=1;j<=2*n;j++)v[j]+=ma[i][j];
}
}
printf("%lld\n",ans);
return 0;
}
H.Second Large Rectangle
题意:
在01矩阵中求出第二大的全1矩阵,只需要输出矩阵大小
分析:
用单调栈求出以第$i$行为底的所有极大全1矩阵,把原矩阵和少一列的矩阵放入结果集,每次保留两个结果
两次单调栈好写,其实一次单调栈也可以求出解
ac代码:
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define pa pair<int,int>
using namespace std;
const int maxn=1e3+5;
const int maxm=1e7+10;
const ll mod=998244353;
char word[maxn][maxn];
int num[maxn][maxn];
int zz[maxn];
int n,m,top,l[maxn],r[maxn];
pa sk[maxn];
int ans[3];
bool vis[maxn][maxn];
void add(int x)
{
ans[0]=x;
sort(ans,ans+3);
}
void work(int x,int y)
{
int v=l[y],w=r[y];
if(vis[v][w])return ;
vis[v][w]=true;
add((w-v)*num[x][y]);
add((w-v+1)*num[x][y]);
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)scanf("%s",word[i]+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(word[i][j]=='1')num[i][j]=num[i-1][j]+1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
while(top&&sk[top].first>num[i][j])
{
r[sk[top].second]=j-1;
top--;
}
sk[++top]=make_pair(num[i][j],j);
}
while(top)r[sk[top].second]=m,top--;
for(int j=m;j>=1;j--)
{
while(top&&sk[top].first>num[i][j])
{
l[sk[top].second]=j+1;
top--;
}
sk[++top]=make_pair(num[i][j],j);
}
while(top)l[sk[top].second]=1,top--;
for(int j=1;j<=m;j++)work(i,j);
for(int j=1;j<=m;j++)vis[l[j]][r[j]]=false,l[j]=r[j]=0;
}
printf("%d\n",ans[1]);
return 0;
}

浙公网安备 33010602011771号