Wannafly挑战赛16

取石子

给出四堆石子,石子数分别为a,b,c,d。规定每次只能从堆顶取走石子,问取走所有石子的方案数。

分析:考虑取出石子的序列长度为a+b+c+d,属于第1堆,第2堆,第3堆,第4堆的分别有a b c d 个

此 答 案 为 C(a+b+c+d,a) C(b+c+d,b) C(c+d,c)=(a+b+c+d)!/(a!b!c!d!)

#include<iostream>
using namespace std;
long long C[2005][2005];
const int mod=1e9+7;
int main()
{
    for(int i=0;i<=2000;++i)
    {
        C[i][0]=1;
        for(int j=1;j<=i;++j)
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    }
    int a,b,c,d;
    cin>>a>>b>>c>>d;
    long long t=C[a+b+c+d][a+b+c]*C[a+b+c][a+b]%mod*C[a+b][a]%mod;
    cout<<t<<"\n";
}

AB序列

#include <bits/stdc++.h>
using namespace std;
int n,m,a[200001];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<=m;i++)
		scanf("%d",&a[i+n]),a[i+n]=-a[i+n];
	n=n+m+1;
	sort(a+1,a+n+1);
	long long sum=0;
	for(int i=1;i<=n;i++)
		sum+=abs(a[i]-a[(n+1)/2]);
	printf("%lld\n",sum); 
	return 0;
} 

小球碰撞

一个弹球(可视为质点)被水平抛出,落地时发生完全弹性碰撞,设弹球第一次落地位置为x,则第i次落地位置为(2i-1)x

若弹球第一次落地的位置在区间[L,R]均匀随机分布,求弹球落在区间[L,R]内的总次数的数学期望值

分析:设第一次落点的位置为x(L<=x<=R) 当x+(k-1)(2x)<=R<x+k(2x) 时碰撞次数为k次

化简得 R/(2k+1)<x<=R/(2k-1)

则期望次数为

最后一步上下同时除以R就很巧妙!!!

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define P 998244353
int a[20000005],b[20000005],i,l,r,n,t;
int main()
{
	for(a[1]=1,i=2;i<10000005;i++)a[i]=(ll)(P-P/i)*a[P%i]%P;
	for(i=1;i<10000005;i++)
	{
		b[i]=b[i-1]+a[i];
		if(b[i]>=P)b[i]-=P;
	}
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&l,&r);
		n=(r+l)/l>>1;
		printf("%d\n",(r*(b[n<<1]+(ll)(P-1>>1)*b[n]%P)%P-(ll)l*n%P+P)*a[r-l]%P);
	}
	return 0;
}

打怪

就是一个简单的dp

设状态为f[i][j][k],表示处理完第i只怪,武器是j,属性是k的最短时间 武器/属性的切换只需在打每只怪之前考虑 转 移的时候,分别考虑武器,属性的转换即

可 由于武器/属性的转换是一个有向图,间接切换可能比直接切换更优, 所以一开始要跑Floyd求最短路。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define P 998244353
ll ans=1LL<<60,f[105][105];
int x[105],y[105],u[105][105],v[105][105],w[105][105][105],s[105],t[105],a,b,n,c,i,j,k,l;
int main()
{
	scanf("%d%d%d%d",&a,&b,&c,&n);
	for(i=1;i<=a;i++)scanf("%d",x+i);
	for(i=1;i<=b;i++)scanf("%d",y+i);
	for(i=1;i<=a;i++)for(j=1;j<=a;j++)scanf("%d",u[i]+j);
	for(i=1;i<=b;i++)for(j=1;j<=b;j++)scanf("%d",v[i]+j);
	for(i=1;i<=c;i++)for(j=1;j<=a;j++)for(k=1;k<=b;k++)scanf("%d",w[i][j]+k);
	for(i=1;i<=n;i++)scanf("%d",s+i);
	for(i=1;i<=n;i++)scanf("%d",t+i);
	for(k=1;k<=a;k++)for(i=1;i<=a;i++)for(j=1;j<=a;j++)u[i][j]=min(u[i][j],u[i][k]+u[k][j]);
	for(k=1;k<=b;k++)for(i=1;i<=b;i++)for(j=1;j<=b;j++)v[i][j]=min(v[i][j],v[i][k]+v[k][j]);
	for(i=1;i<=a;i++)for(j=1;j<=b;j++)f[i][j]=x[i]+y[j];
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=a;j++)for(k=1;k<=b;k++)for(l=1;l<=a;l++)f[j][k]=min(f[j][k],f[l][k]+u[l][j]);
		for(j=1;j<=a;j++)for(k=1;k<=b;k++)for(l=1;l<=b;l++)f[j][k]=min(f[j][k],f[j][l]+v[l][k]);
		for(j=1;j<=a;j++)for(k=1;k<=b;k++)f[j][k]+=(s[i]+w[t[i]][j][k]-1)/w[t[i]][j][k];
	}
	for(i=1;i<=a;i++)for(j=1;j<=b;j++)ans=min(ans,f[i][j]);
	cout<<ans<<endl;
	return 0;
}
posted @ 2022-08-11 10:25  wzx_believer  阅读(25)  评论(0编辑  收藏  举报