看程序写结果(program)

时间:2022-08-06 05:40:01

看程序写结果(program)

Time Limit:1000ms Memory Limit:64MB

题目描述

LYK 最近在准备 NOIP2017 的初赛,它最不擅长的就是看程序写结果了,因此它拼命地
在练习。
这次它拿到这样的一个程序:

Pascal:
readln(n);
for i:=1 to n do read(a[i]);
for i:=1 to n do for j:=1 to n do for k:=1 to n do for l:=1 to n do
if (a[i]=a[j]) and (a[i]<a[k]) and (a[k]=a[l]) then ans:=(ans+1) mod 1000000007;
writeln(ans);

C++:
scanf(“%d”,&n);
for (i=1; i<=n; i++) scanf(“%d”,&a[i]);
for (i=1; i<=n; i++) for (j=1; j<=n; j++) for (k=1; k<=n; k++) for (l=1; l<=n; l++)
if (a[i]==a[j] && a[i]<a[k] && a[k]==a[l]) ans=(ans+1)%1000000007;
printf(“%d\n”,ans);

LYK 知道了所有输入数据,它想知道这个程序运行下来会输出多少。

输入格式(program.in)

第一行一个数 n,第二行 n 个数,表示 ai。

输出格式(program.out)

一个数表示答案。

输入样例

4
1 1 3 3

输出样例

16

数据范围

对于 20%的数据 n<=50。
对于 40%的数据 n<=200。
对于 60%的数据 n<=2000。
对于 100%的数据 n<=100000,1<=ai<=1000000000。
其中均匀分布着 50%的数据不同的 ai 个数<=10,对于另外 50%的数据不同的 ai 个
数>=n/10。

思路:

  我们现在分析一下这个c++代码

pcanf(“%d”,&n);
for (i=; i<=n; i++) scanf(“%d”,&a[i]);
for (i=; i<=n; i++) for (j=; j<=n; j++) for (k=; k<=n; k++) for (l=; l<=n; l++)
if (a[i]==a[j] && a[i]<a[k] && a[k]==a[l]) ans=(ans+)%;
printf(“%d\n”,ans);

  这段代码里面有4重循环大概n==100就差不多爆时间

  所以我们要优化

  其中有两重循环可以简化为O(1);

  那就是第一重和最后一重

  就是询问有在这个数组里有几个和这个元素值相等的元素

  我们可以把所有的元素值记录下来

  然后离散化使之成为存储每个元素个数的数组

  然后每个数组的值都是这个元素个数的平方

  现在再看第二重和第三重循环

  这个是用来比较大小的

  于是

  我想到了前缀和

  就是把比当前元素个数的平方和记录下来

  然后每次取值就用前缀和就好

  经优化后成为一个O(n)时间复杂度的算法

  来,上代码:

#include<cstdio>
#include<iostream>
#include<algorithm> #define mod 1000000007LL using namespace std; long long int b[],n,ans;
long long int sum[]; int a[],head; char ch; void qread(long long int &x)
{
x=;ch=getchar();
while(ch>''||ch<'') ch=getchar();
while(ch<=''&&ch>=''){x=x*+(int)(ch-'');ch=getchar();}
} int main()
{
qread(n);
for(int i=;i<=n;i++) qread(b[i]);
sort(b+,b+n+);
for(int i=;i<=n;i++)
{
if(b[i]!=b[i-]) head++;
a[head]++;
}
for(int i=;i<=head;i++) a[i]=a[i]*a[i]%mod,sum[i]=(sum[i-]+(a[i]%mod))%mod;
for(int i=;i<=head;i++) ans=(ans+((sum[i-]*a[i])%mod))%mod;
cout<<ans<<endl;
return ;
}