Rank:67 / 297 (不过榜单好像不是现场的榜单)
这次韩巍有课没来,我和程磊两个人做的,这次做的是女生赛,沃老师出的题,题面都是中文题,比较友好,题目都比较简单,都是思维题,一共做出来6个题(终于破了做不出第六题的魔咒......)
签到题。
签到题。写出前几项找规律就行了。
签到题。可以发现,当第n+1个点是“圆心和某两个点之间的中点的连线与圆的交点”时面积最大,推公式就行了。
推公式。第一次加6,第二次加7,第三次加8......
只有当n和m都是4的倍数的时候才能拼凑成,至于怎么拼成,把样例一粘就行了。
这个题我过的时候感觉还挺惊奇的......就是把这n个时间看作n个点,每个点的值就是把时刻转换成秒(如果小时大于等于12,那么就让h-=12),然后每个点连出去两条边,构成一个n个点n条边的环,然后初始时刻往环里切入,至于从哪切入,for一遍取最小值就是答案。刚才说的每个点都向外连两条边是连向离它最近的两个点连边,每条边的大小就是顺时针和逆时针到达那个点的的距离取最小值。说的不太清楚,反正就这样。
ACcode:
#include<bits/stdc++.h>
typedef long long ll;
const ll N=90000;
const ll inf=1e15+10;
using namespace std;
ll n,H,M,S;
ll h[N],m[N],s[N];
ll a[N],b[N];
int main()
{
while(scanf("%lld",&n)!=EOF)
{
scanf("%lld%lld%lld",&H,&M,&S);
if(H>=12)
H-=12;
ll num=H*3600+M*60+S;
for(int i=1;i<=n;i++)
{
scanf("%lld%lld%lld",&h[i],&m[i],&s[i]);
if(h[i]>=12)
h[i]-=12;
a[i]=h[i]*3600+m[i]*60+s[i];
}
ll ans=inf;
if(n==1)
{
if(num>a[1])
ans=min(num-a[1],a[1]+12*3600-num);
else
ans=min(a[1]-num,num+12*3600-a[1]);
double anss=ans;
anss*=6;
printf("%.2f\n",anss);
continue;
}
sort(a+1,a+n+1);
for(int i=1;i<=n-1;i++)
b[i]=min(a[i+1]-a[i],a[i]+12*3600-a[i+1]);
b[n]=min(a[n]-a[1],a[1]+12*3600-a[n]);
ll sum=0;
for(int i=1;i<=n;i++)
sum+=b[i];
for(int i=1;i<=n;i++)
{
if(a[i]>num)
{
if(i==1)
ans=min(ans,min(a[i]-num,num+12*3600-a[i])+sum-max(b[1],b[n]));
else
ans=min(ans,min(a[i]-num,num+12*3600-a[i])+sum-max(b[i],b[i-1]));
}
else
{
if(i==1)
ans=min(ans,min(num-a[i],a[i]+12*3600-num)+sum-max(b[1],b[n]));
else
ans=min(ans,min(num-a[i],a[i]+12*3600-num)+sum-max(b[i],b[i-1]));
}
}
double anss=ans;
anss*=6;
printf("%.2f\n",anss);
}
return 0;
}
树链刨分+线段树区间开方区间求和模板题。
详见一下两篇博客:
https://blog.csdn.net/flyzer/article/details/102487521
https://blog.csdn.net/flyzer/article/details/102477838
啊,这个题就是贪心一下(感觉这场题都很妙)。
f(x+1)-f(x)=a*(x+1)*(x+1)+b*x+c-(a*x*x+b*x+c)=a*(2*x+1)+b。
然后用set存,每次贪心的选择增加的最少的那个。详见代码。
#include<bits/stdc++.h>
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<<endl<<endl<<endl
#define IT set<nodee>::iterator
typedef long long ll;
const ll inf=0x3f3f3f3f;
const ll N=100010;
using namespace std;
ll n,m;
struct node{
ll a,b,c;
}e[100010];
struct nodee{
ll id;
ll num;
bool operator < (const nodee& bb)const{
if(num!=bb.num)
return num<bb.num;
if(num==bb.num)
return id<bb.id;
//这里这么写是因为:不能有重复的元素,因为set是去重的,但我不想让它去重
//return num<bb.num;
}
}d[100010];
ll cnt[100010];
set<nodee> s;
int main()
{
mem(cnt,0);
while(scanf("%lld%lld",&n,&m)!=EOF)
{
for(ll i=1;i<=n;i++)
scanf("%lld%lld%lld",&e[i].a,&e[i].b,&e[i].c);
for(ll i=1;i<=n;i++)
{
d[i].id=i;
d[i].num=e[i].a*(2*1+1)+e[i].b;
s.insert(d[i]);
cnt[i]++;
}
m-=n;
while(m--)
{
IT it=s.begin();
ll id=(*it).id;
cnt[id]++;
s.erase(it);
nodee itt=(*it);
itt.num=e[id].a*(cnt[id]*2+1)+e[id].b;
s.insert(itt);
}
ll ans=0;
for(ll i=1;i<=n;i++)
ans+=e[i].a*cnt[i]*cnt[i]+e[i].b*cnt[i]+e[i].c;
printf("%lld\n",ans);
for(int i=1;i<=n;i++)
cnt[i]=0;
}
return 0;
}
额,dp,尽管沃老师在camp上讲过了,当时我好像会了,然后又不会了......
这个题有点奇葩,同样的代码,交几遍,有时候AC,有时候T,好像其他人对这个题也是这样。
这篇博客讲的挺好的:https://www.cnblogs.com/kangkang-/p/11642022.html
下面是我有时候AC有时候T的代码:
#include<bits/stdc++.h>
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<<endl<<endl<<endl
typedef long long ll;
const int inf=1e8;
const int N=100010;
using namespace std;
int n,l,k;
int dp[N][28][12],pre[N][28][12],suf[N][28][12];
char a[N];
void init()
{
for(int i=0;i<=n+1;i++)
for(int j=0;j<=27;j++)
for(int p=0;p<=k+1;p++)
dp[i][j][p]=inf,pre[i][j][p]=inf,suf[i][j][p]=inf;
}
int main()
{
scanf("%d%d%d",&n,&l,&k);
scanf("%s",a+1);
init();
for(int j=1;j<=26;j++)
{
if(a[1]-'a'+1==j)
dp[1][j][1]=0;
else
dp[1][j][1]=1;
}
for(int j=1;j<=26;j++)
for(int p=1;p<=k;p++)
pre[1][j][p]=min(pre[1][j-1][p],dp[1][j][p]);
for(int j=26;j>=1;j--)
for(int p=1;p<=k;p++)
suf[1][j][p]=min(suf[1][j+1][p],dp[1][j][p]);
for(int i=2;i<=n;i++)
{
for(int j=1;j<=26;j++)
for(int p=1;p<=k;p++)
{
if(a[i]==j+'a'-1)
dp[i][j][p]=min(min(dp[i-1][j][p],pre[i-1][j-1][p-1]),suf[i-1][j+1][p-1]);
else
{int q=max(i-l,1);dp[i][j][p]=min(min(dp[q][j][p],pre[q][j-1][p-1]),suf[q][j+1][p-1])+1;}
}
for(int j=1;j<=26;j++)
for(int p=1;p<=k;p++)
pre[i][j][p]=min(pre[i][j-1][p],dp[i][j][p]);
for(int j=26;j>=1;j--)
for(int p=1;p<=k;p++)
suf[i][j][p]=min(suf[i][j+1][p],dp[i][j][p]);
}
int ans=inf;
for(int j=1;j<=26;j++)
for(int p=1;p<=k;p++)
ans=min(ans,dp[n][j][p]);
printf("%d\n",ans);
return 0;
}
转载:https://blog.csdn.net/flyzer/article/details/102489953