目录
题目链接https://ac.nowcoder.com/acm/contest/11256
B - Boxes
题目
有n个箱子,每个箱子里白球和黑球的可能性为1/2,开一个箱子需要花费wi,可以花费c元知道剩余盒子中黑球的数目,求最小花费
思路
一开始还是有点混乱的@_@
- 首先,只需要在最开始的时候花费c,这样就知道之后的黑球的数目
- 之后每次打开盒子全为黑或白的概率为 1 − 1 2 n − i 1-\frac{1}{2^{n-i} } 1−2n−i1
- 把wi从小到大排序然后计算比较
代码
#include<bits/stdc++.h>
using namespace std;
int n;
double w[100010],sum[10010],c;
int main()
{
cin>>n>>c;
for(int i=1;i<=n;i++)
{
cin>>w[i];
}
sort(w+1,w+n+1);
double ans=c;
for(int i=1;i<=n;i++)
{
ans+=sum[i-1]*pow(0.5,n-i+1);
sum[i]=sum[i-1]+w[i];
}
printf("%.7f\n",min(sum[n],ans));
return 0;
}
D - Double Strings
题目
感觉题目才是最难懂的(( ̄、 ̄))
思路
就是有两个字符串s1和s2,找到有多少个子序列满足:
① 两个子序列长度相等
② 第x位时,s1[x]<s2[x]
③ <x时,s1[i]==s2[i]
④ >x时,任意
然后可以模拟排列组合,或者用数组w表示(这个很容易卡内存,所以要使用int,在计算中间转换)
代码
#include<bits/stdc++.h>
#define mod 1000000007
#define maxx 5005
using namespace std;
typedef long long ll;
char s1[maxx],s2[maxx];
int dp[maxx][maxx],w[maxx][maxx];
int main()
{
scanf("%s%s",s1+1,s2+1);
int len1=strlen(s1+1);
int len2=strlen(s2+1);
dp[0][0]=1;
w[0][0]=1; //一开始忘记了,我说咋不对
for(int i=1; i<5005; i++)
{
dp[0][i]=dp[i][0]=1;
w[0][i]=w[i][0]=1;
}
for(int i=1; i<=len1; i++)
{
for(int j=1; j<=len2; j++)
{
w[i][j]=(w[i][j-1]+w[i-1][j])%mod;
//cout<<w[i][j]<<' ';
}
//cout<<endl;
}
for(int i=1; i<=len1; i++)
{
for(int j=1; j<=len2; j++)
{
if(s1[i]==s2[j])
dp[i][j]=(dp[i-1][j]+dp[i][j-1])%mod;
else
dp[i][j]=((ll)dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1])%mod; //在计算过程中间改
// cout<<dp[i][j]<<' ';
}
// cout<<endl;
}
ll ans=0;
for(int i=1; i<=len1; i++)
{
for(int j=1; j<=len2; j++)
{
if(s1[i]<s2[j])
{
ans+=((ll)dp[i-1][j-1]%mod*w[len1-i][len2-j]%mod)%mod;
}
}
}
cout<<(ans)%mod;
return 0;
}
总结
1.注意scanf从第一位开始读的写法
2.模拟的代码 还没看
ll pow_m(ll a,ll k,ll p)
{
ll ans=1;
ll tmp=a%p;
while(k)
{
if(k&1)ans=ans*tmp%p;
tmp=tmp*tmp%p;
k>>=1;
}
return ans;
}
ll C(ll n,ll m,ll p)
{
if(m>n)return 0;
ll a=1,b=1;
for(int i=1;i<=m;i++)
{
a=a*(n+i-m)%p;
b=b*i%p;
}
return a*pow_m(b,p-2,p)%p;
}
ll Lucas(ll n,ll m,ll p)
{
ll ans=1;
while(n&&m)
{
ans=ans*C(n%p,m%p,p)%p;
n/=p;
m/=p;
}
return ans;
}
H - Holding Two
签到,就是构造00110011,11001100,。。。,的矩阵
K - King of Range
题目
求区间满足(最大值-最小值>k)的个数
思路
对于1,4,3,2,5,当k=2时,如果找到一对符合的,那么这个数之后所有的区间都符合
如(1,4)>2,那么区间(1,3),(1,2),(1,5)肯定是符合的
所以只需要维护两个单调序列,里面是当前区间的最大值和最小值
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e7+100;
ll a[maxn];
ll qmax[maxn];
ll qmin[maxn];
int main()
{
int n,m;
cin>>n>>m;
for(int i=1; i<=n; i++)
{
cin>>a[i];
}
while(m--)
{
ll k;
cin>>k;
ll ans=0,l=1,h1=1,t1=0,h2=1,t2=0;
for(int i=1; i<=n; i++)
{
while(h1<=t1 && a[i]>=a[qmax[t1]])
t1--;
while(h2<=t2 && a[i]<=a[qmin[t2]])
t2--;
qmax[++t1]=i;
qmin[++t2]=i;
while(h1<=t1 && h2<=t2 && a[qmax[h1]]-a[qmin[h2]]>k)
{
ans+=n-i+1;//计算权值
l++;
if(qmax[h1]<l)
h1++;
if(qmin[h2]<l)
h2++;
}
}
cout<<ans<<endl;
}
return 0;
}
/*
5 2
1 5 9 3 4
4
*/
下面是队列的做法
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int a[maxn];
int main()
{
int n,m,k;
scanf("%d%d",&n,&m);
for (int i= 1;i<=n;i++)
scanf("%d",&a[i]);
while(m--)
{
cin>>k;
deque<int> qMax,qMin;//单调队列
ll ans=0;
for(int l=1,r=1;r<=n;++r)
{
while(qMax.size()&&a[qMax.back()]<a[r])//只要qmax最尾部的数小于a[r],就不断弹出
qMax.pop_back();
qMax.push_back(r);//然后将r放进去
while(qMin.size()&&a[qMin.back()]>a[r])
qMin.pop_back();
qMin.push_back(r);
while(a[qMax.front()]-a[qMin.front()]>k)
{
ans+=(ll)n-r+1;
l++;
if(qMax.front()<l)//向右移动l,如果队列最大值的编号小于l就弹出
qMax.pop_front();
if(qMin.front()<l)
qMin.pop_front();
}
}
printf("%lld\n",ans);
}
}
J - Jewels
题目
思路
二分图最大匹配问题
https://www.cnblogs.com/logosG/p/logos.html
代码
三次方的写法
//DFS
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define M(a,b) memset(a,b,sizeof a)
const int N=450;
ll w[N][N],lx[N],ly[N],slk[N];
int lft[N],S[N],T[N],pre[N],last[N],nl,nr,n,m;
ll ans;
bool dfs(int x)
{
S[x]=1;
for(int i=1; i<=n; i++)
if(!T[i])
{
if(lx[x]+ly[i]==w[x][i])
{
T[i]=1;
last[i]=x;
pre[lft[i]]=i;
if(!lft[i]||dfs(lft[i]))
{
lft[i]=x;
return 1;
}
}
else if(slk[i]>lx[x]+ly[i]-w[x][i])
{
last[i]=x;
slk[i]=lx[x]+ly[i]-w[x][i];
}
}
return 0;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n;
nl=nr=n;
for(int i=1; i<=n; ++i)
{
int x,y,z,v;
cin>>x>>y>>z>>v;
ans+=x*x+y*y+(ll)(z+n*v)*(z+n*v);
for(int j=0; j<n; ++j)
{
ll t=(ll)(z+n*v)*(z+n*v)-(ll)(z+j*v)*(z+j*v);
w[i][j+1]=t;
lx[i]=max(lx[i],t);
// cout<<w[i][j+1]<<' ';
}
// cout<<endl;
}
for(int i=1,u,y; i<=n; i++)
{
ll a;
M(S,0);
M(T,0);
M(pre,0);
M(last,0);
M(slk,0x3f);
for(u=i; u&&!dfs(u); pre[u=lft[y]]=y)
{
a=0x3f3f3f3f3f3f3f3fll;
for(int i=1; i<=n; i++)
{
if(!T[i] && slk[i]<a)
{
a=slk[i];
y=i;
}
}
for(int i=1; i<=n; i++)
{
if(S[i])
lx[i]-=a;
if(T[i])
ly[i]+=a;
else slk[i]-=a;
}
T[y]=1;
}
for(; u!=i;)
{
u=pre[u];
lft[u]=last[u];
u=last[u];
}
}
for(int i=1; i<=n; i++)
ans-=lx[i]+ly[i];
cout<<ans<<'\n';
return 0;
}