在你的历史课上,你得到了一个很长的作业。这个作业包含了N个题目(3≤N≤100,000),每个题目的成绩在0~10,000之间。
按照惯例,你的老师按照以下方式计算最终成绩:去掉你最低的一个成绩,然后将其余成绩的平均成绩作为最终成绩。但不幸的是,你的宠物牛“贝西”刚刚吃了前K个题目的答案!(1≤K≤N-2)
经过你的一番解释,老师终于相信了你的故事,并且同意对你有答案的题目(没有被吃掉答案的题目)像之前一样给分——通过去掉最低的成绩(如果有多个最低成绩,则只去掉其中一个)并取剩余成绩的平均成绩。
根据这一成绩计算方案,请按升序输出所有可以使你最终成绩最高的K的值。
预处理出前缀和和区间最小值,暴力枚举
#include
using namespace std;
long long n,a[100010],sum[100010],minn[100010],ans=1,res[100010],cnt=1;
int main()
{
memset(sum,0,sizeof(sum)),memset(minn,0x3f,sizeof(minn)),res[1]=1,scanf("%lld",&n);
for(long long i=1;i<=n;i++)scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i];
for(long long i=n;i>=1;i--)minn[i]=min(minn[i+1],a[i]);
for(long long i=2;i<=n-2;i++)
if((sum[n]-sum[i]-minn[i+1])*(n-ans-1)>(sum[n]-sum[ans]-minn[ans+1])*(n-i-1))ans=i,res[1]=i,cnt=1;
else if((sum[n]-sum[i]-minn[i+1])*(n-ans-1)==(sum[n]-sum[ans]-minn[ans+1])*(n-i-1))res[++cnt]=i;
for(int i=1;i<=cnt;i++)printf("%d\n",res[i]);
return 0;
}
最初,农夫约翰的每头奶牛每天生产G加仑的牛奶(1≤G≤10^9)。由于随着时间的推移,奶牛的产奶量可能会发生变化,农夫约翰决定定期对奶牛的产奶量进行测量,并将其记录在日志中。
他的日志中的记录如下:
35 1234 -2
14 2345 +3
第一个条目表明:在第35天,1234号奶牛的产奶量比上次测量时降低了2加仑。
第二个条目表明:在第14天,2345号奶牛的产奶量比上次测量时增加了3加仑。
农夫约翰只有在任何一天内做最多一次测量的时间(即每天最多做一次测量,但可能不做)。不幸的是,约翰有点杂乱无章,他不一定按照时间顺序记下测量结果。为了保持奶牛的产奶动力,农夫约翰自豪地在谷仓的墙上展示了目前产奶量最高的奶牛的照片(如果有若干头奶牛的产奶量最高,他就会展示所有的图片)。
请求出约翰需要调整所展示的照片的次数。
请注意,农夫约翰有一大群奶牛。所以尽管日志中记录了一些奶牛改变了产奶量,但仍然还有很多奶牛的产奶量保持在G加仑。
看题解写的都是线段树,我这么蒟,不会线段树怎么办qwq,我们就来打模拟吧
有几个坑点:
1.当第一名的奶牛产奶量变化,但奶牛编号不变时,不会换照片
2.题目中最后一句话是什么意思呢,就是说一定有奶牛保持在G加仑,也就是说,如果当前计算出来奶牛的最高产奶量不足G加仑,那么贴着照片的不是这头奶牛,而是那些G加仑的奶牛
3.关于具体的模拟做法,就放在程序里吧
#include
#define u mp[a[i].m]
#define ch a[i].s
using namespace std;
struct node{int t,m,s;}a[101010];
bool cmp(node x,node y){return x.tmp;
void find()
{
se=-0x3f3f3f3f,ses=0;
for(int i=1;i<=cnt;i++)
if(cow[i]!=fi&&cow[i]>se)se=cow[i],ses=1;
else if(cow[i]==se)ses++;
}
//重新寻找第二名
int main()
{
memset(cow,0,sizeof(cow)),scanf("%d%d",&n,&g);
for(int i=1;i<=n;i++)scanf("%d%d%d",&a[i].t,&a[i].m,&ch);
sort(a+1,a+1+n,cmp);
//先按照记录时间排序
for(int i=1;i<=n;i++)
{
if(!u)u=++cnt;
//u的定义看上面的define
//这里就是把编号离散化一下
if(cow[u]==fi)
//第一种情况,当前处理的奶牛是排位第一的
{
cow[u]+=ch;
if(ch>0)
//如果产奶量上升
{
if(fis!=1)se=fi,ses=fis-1,fi=cow[u],fis=1,ans++;
//如果有很多排位第一的奶牛
//这些奶牛变成第二名,当前奶牛独占第一,照片墙会替换
else fi=cow[u];
//如果只有一头排位第一的奶牛,照片墙不会替换
}
else
//如果产奶量下降
{
if(fis!=1)
//如果有很多排位第一的奶牛
{
fis--,ans++;
//排位第一的奶牛的数量减少,照片墙替换
if(cow[u]>se)se=cow[u],ses=1;
//如果当前奶牛的产奶量比第二名大
//第二名就变成当前奶牛
if(cow[u]==se)ses++;
//如果当前奶牛的产奶量等于第二名
//第二名奶牛数量增加
}
else
//如果只有一头排位第一的奶牛
{
if(cow[u]>se)fi=cow[u];
//如果还比排名第二的产奶量大,照片墙不改变
if(cow[u]==se)fi=se,fis=ses+1,ans++,find();
//如果等于排名第二的产奶量,第二上升为第一,重新寻找第二名
if(cow[u]fi)swap(se,fi),swap(ses,fis),ans++;
//还有可能替换第一名,此时照片墙替换
}
}
}
else
//如果不是第一第二名
{
cow[u]+=ch;
if(cow[u]==se)ses++;
if(cow[u]==fi)fis++,ans++;
//如果变成了第一名,照片墙替换
else if(cow[u]>se)
//如果超越第二名但没有变成第一名
{
se=cow[u],ses=1;
//至少成为第二名
if(se>fi)swap(se,fi),swap(ses,fis),ans++;
//还有可能替换第一名,此时照片墙替换
}
}
}
printf("%d\n",ans);
//可能注释有点啰嗦,请见谅qwq
return 0;
}
FJ坚信快乐的牛可以产出更多的牛奶,因此FJ在牛棚里安装了一个巨大的迪斯科球并且打算让奶牛们学会尬跳舞。
FJ在许多出名的奶牛舞中选择了一种叫做”Bovine Shuffle”的舞蹈。这种舞蹈由FJ的N头奶牛组成。N头奶牛以一种顺序排成一行,接着表演数次”shuffle”。每次的”shuffle”会将奶牛重新排列。FJ为了让奶牛们更加happy,让奶牛们更容易找到重新排列后的位置,他标记了N头奶牛的位置。在最开始,所有奶牛排成一排,第一头奶牛会在位置1(坐标?)上,第二只在2上,以此类推。
我们用N个正整数a_1,a_2…a_n来描述每次的”shuffle”。a_i说明了在位置i上的奶牛在经过这回合的”shuffle”之后,会跑到位置a_i上。令FJ倍感非洲的是,即使i与j不同,a_i也可能会等于a_j!所以可能在一次”shuffle”后,有多头奶牛会跑到同一位置上,在这之后这群奶牛也会一同行动。
作为一名资深的养牛大户&坑牛专家的FJ猛然发现,无论经过多少次的”shuffle”,一直都有k个位置上有奶牛。FJ现在要你在1s1s 内帮他得出k的值,否则就赏你1e18mod10大板!
看了正解都是些图论判环,我们来打玄♂学算法
我们就按照它的步骤模拟,若干次之后看该位置是否还有奶牛
注意要双向模拟
#include
using namespace std;
int n,a[100005],b[100005],c[100005],ans=0;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)a[i]=b[i]=1,scanf("%d",&c[i]);
for(int i=1;i<=1000;i++)
{
for(int i=1;i<=n;i++)b[c[i]]+=a[i];
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)a[c[i]]+=b[i];
memset(b,0,sizeof(b));
}
for(int i=1;i<=n;i++)if(a[i]||b[i])ans++;
printf("%d",ans);
return 0;
}