這輩子不想講題了
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: