20240713比賽總結

wangsiqi2010916發表於2024-07-13

這輩子不想講題了

T1 炒幣

https://gxyzoj.com/d/hzoj/p/3798

57pts:

dp,設\(dp_{0/1,i}\)表示第i天有人民幣/比特幣的最大值,mx,nx就是前面的最大值

\(dp_{0,i}=dp_{1,mx}\div a_i\)

\(dp_{1,i}=dp_{0,nx}\times a_i\)

但是顯然會炸long double

solution 1:

因為我們不關心具體的值,只關心轉移的指標,所以可以進行一些改進,可以透過比較比值來找到最值

可以發現,\(\dfrac{dp_{0,i}}{dp_{1,mx}}=\dfrac{dp_{0,nx}}{dp_{1,i}}=a_i\)

所以,當\(\dfrac{dp_{0,i}}{dp_{1,mx}}>\dfrac{dp_{0,mx}}{dp_{1,mx}}\)\(a_i>a_{mx}\)時,就更新mx

\(\dfrac{dp_{0,nx}}{dp_{1,i}}>\dfrac{dp_{0,nx}}{dp_{1,nx}}\)\(a_i>a_{nx}\)時,就更新nx

程式碼:

#include<cstdio>
#include<iostream>
using namespace std;
int n,a[200005],pre1,pre2,pre[200005][2];
long double dp[200005][2],sum1,sum2,p;
int vis[200005];
int main()
{
//	freopen("1.txt","r",stdin);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	sum1=1.0,pre1=0,sum2=a[1]*1.0,pre2=1;
	p=sum2/sum1;
	for(int i=2;i<=n;i++)
	{
//		dp[i][0]=sum2/(1.0*a[i]);
//		dp[i][1]=sum1*(1.0*a[i]);
//		pre[i][0]=pre2,pre[i][1]=pre1;
//		if(dp[i][0]>sum1)
//		{
//			sum1=dp[i][0],pre1=i;
//		}
//		if(dp[i][1]>sum2)
//		{
//			sum2=dp[i][1],pre2=i;
//		}
		pre[i][0]=pre2,pre[i][1]=pre1;
		if(a[i]*1.0>p) pre2=i;
		if(a[i]*1.0<p) pre1=i;
		p=1.0*a[i];
	}
	int lst=pre1,st=1;
//	for(int i=1;i<=n;i++)
//	{
//		if(dp[i][0]>dp[lst][0])
//		{
//			lst=i;
//		}
//	}
	while(lst!=0)
	{
		st^=1;
		vis[lst]=1;
		lst=pre[lst][st];
	}
	for(int i=1;i<=n;i++)
	{
		printf("%d ",vis[i]);
	}
	return 0;
}

solution 2:

低買高賣,直接貪心

在峰值買入,谷值賣出,為防止買後不賣出,可以將n+1設為inf

T2 湊數

https://gxyzoj.com/d/hzoj/p/3799

30pts:

暴力揹包

30~80pts:

列舉1,a,b的個數+特判

100pts:

\(\dfrac{y}{a}<\dfrac{z}{b}\)

當有a個b和b個a時,顯然選b個a更優,所以,選b的個數不會超過a

而選a的次數不會超過\(\lfloor \dfrac{n}{a} \rfloor\),這兩個數中,必然有一個不超過\(\sqrt{n}\),取最小的列舉即可

程式碼:

#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
int T,n;
ll minn;
struct node{
	ll cost,val;
	double avg;
}a[5];
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		scanf("%lld%lld",&a[2].val,&a[3].val);
		scanf("%lld%lld%lld",&a[1].cost,&a[2].cost,&a[3].cost);
		a[1].val=1;
		for(int i=1;i<=3;i++)
		{
			a[i].avg=a[i].cost*1.0/(1.0*a[i].val);
		}
		if(a[2].avg>a[3].avg) swap(a[2],a[3]);
		ll x=n/a[2].val;
		ll tmp=n-x*a[2].val;
		minn=1ll*tmp*a[1].cost+1ll*x*a[2].cost;
		minn=min(minn,1ll*a[1].cost*n);
		if(a[1].cost<a[3].avg||tmp==0)
		{
			printf("%lld\n",minn);
			continue;
		}
		if(a[2].val<n/a[2].val)
		{
			for(int i=0;i<=a[2].val;i++)
			{
				ll y=n-i*a[3].val;
				if(y<0) continue;
				x=y/a[2].val;
				tmp=y-x*a[2].val;
				minn=min(minn,1ll*tmp*a[1].cost+1ll*x*a[2].cost+1ll*a[3].cost*i);
			}
		}
		else
		{
			for(int i=0;i<=n/a[2].val;i++)
			{
				ll y=n-i*a[2].val;
				if(y<0) continue;
				x=y/a[3].val;
				tmp=y-x*a[3].val;
				minn=min(minn,1ll*tmp*a[1].cost+1ll*x*a[3].cost+1ll*a[2].cost*i);
			}
		}
		printf("%lld\n",minn);
	}
	return 0;
}

T3 同構

抽象的結論題

10~20pts:直接DFS即可

void dfs(int x)
{
	if(x>n)
	{
		ans=(ans+1)%1000000007;
		return;
	}
	for(int i=1;i<=n;i++)
	{
		if(!b[i])
		{
			bool fl=0;
			for(int j=1;j<x;j++)
			{
				int tmp1=(gcd(a[j],i)==1),tmp2=(gcd(j,x)==1);
				if(tmp1!=tmp2)
				{
					fl=1;
					break;
				}
			}
			if(!fl)
			{
				b[i]=1,a[x]=i;
				dfs(x+1);
				b[i]=0;
			}
		}
	}
}

100pts: