2020沈阳区域赛补题&总结
7月18号的比赛,一直拖着没补。想想就这样放着不太行,还是开个坑慢慢填吧
考前一个月备战期末没摸acm,最后rank85/265,罚时卡出ag线,大概就是报应吧。
D. Journey to Un'Goro
构造。
很关键的一个想法:令\(p_i\)表示从\(1\)到\(i\)位置中\(r\)数量的奇偶性,\(i\)到\(j\)中\(r\)的数量为奇数的条件便是\(p_{i-1},p_j\)不同。(特别地,\(p_0\)为偶)
那么对于\(n\)的一种构造方式,考虑有\(x\)个奇数点,\(n+1-x\)个偶数点,那么题中要求的\((i,j)\)对数就是\(x*(n-x+1)\)。均值不等式,想要最大化合法对数就是使得奇偶点数为\(\lceil\frac{n+1}{2}\rceil\)和\(\lfloor\frac{n+1}{2}\rfloor\)(谁大谁小都行),然后就排列就是了。由于从第\(0\)位开始且该位确定是偶,所以排列确定,你的\(br\)序列也就定了。排列中当前位与前一位不同,这一位就是\(r\),反之是\(b\)。
那么dfs就行了,贪心从前往后做一位一位的做,在满足奇偶点的数量约束的前提下(\(\lceil\frac{n+1}{2}\rceil\)),优先保证当前位与前一位奇偶相同(也就是填\(b\)),搜到了100个答案就直接终止。
#include<bits/stdc++.h>
using namespace std;
int n,tot=0;
int ans[100005],num[2];
void dfs(int len)
{
if(tot>=100)
return;
if(len>n)
{
for(int i=1;i<=n;i++)
{
if(ans[i]==ans[i-1])
printf("b");
else
printf("r");
}
tot++;
if(tot>=100)
exit(0);
printf("\n");
return;
}
int p=ans[len-1];
if(num[p]<n/2+1)
{
num[p]++;
ans[len]=p;
dfs(len+1);
num[p]--;
}
p=p^1;
if(num[p]<n/2+1)
{
num[p]++;
ans[len]=p;
dfs(len+1);
num[p]--;
}
}
int main()
{
scanf("%d",&n);
long long p=n;
ans[0]=0;
num[0]=1;
num[1]=0;
printf("%lld\n",(p+1ll)/2ll*(p/2ll+1ll));
dfs(1);
return 0;
}
H. The Boomsday Project
传送门
先考虑怎么暴力
显然你一定是把一张优惠卡用到不能用了(时间限制或次数限制)
将每次租车按时间排序,\(dp[i]\)表示恰好处理完前\(i\)次租车的最小花费,\(f[i][j]\)表示在第\(i\)次用第\(j\)张卡,能覆盖到的最后租车是那次,\(f\)数组可以二分查找来得出
转移:
再考虑怎么优化掉这个\(log\)
注意到\(f\)数组具有单调性:
事实上我们每次算\(f[i][j]\)时,只需要从\(f[i-1][j]\)开始递推,一个一个地往后挪即可
特别地,为了防止MLE,f数组需要使用滚动数组
#include<bits/stdc++.h>
using namespace std;
int n,m,r,p,q,cnt=0;
int d[505],k[505],c[505],rt[300005],f[2][505];
long long dp[300005];
int main()
{
memset(f,0,sizeof(f));
scanf("%d%d%d",&n,&m,&r);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&d[i],&k[i],&c[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&p,&q);
for(int j=cnt+1;j<=cnt+q;j++)
{
rt[j]=p;
dp[j]=1e18;
}
cnt+=q;
}
sort(rt+1,rt+1+cnt);
dp[0]=0;
rt[0]=0;
for(int i=0;i<=cnt-1;i++)
{
dp[i+1]=min(dp[i+1],dp[i]+1ll*r);
for(int j=1;j<=n;j++)
{
for(int l=f[0][j];l<=cnt;l++)
{
if(l-i<=k[j]&&rt[l]-rt[i+1]<=d[j]-1)
f[1][j]=l;
else
break;
}
f[0][j]=f[1][j];
dp[f[0][j]]=min(dp[i]+1ll*c[j],dp[f[0][j]]);
//printf("%d %d %d %lld %lld\n",i,j,f[0][j],dp[i],dp[i+f[0][j]]);
}
}
printf("%lld",dp[cnt]);
return 0;
}