2015多校联赛第一场
对于弱渣,表示只过了两题。。。还都是水题。。。
1001.
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5288
题意:给定一个整数n,然后l的取值是1~n,r的取值是i~n,求每个i,j范围内有多少个a[i]满足,除自己以外没有其它因子。
题解:如果从区间暴力,n^4,绝笔超时。然后发现a[i]的范围只有10000,那么通过查找每个数字的[l,r],算出能够满足多少个空间,把所有满足的数值加起来即可,不过如果都扫一遍,n^2还是超时。(楼主就这样T了一发),之后通过标记因子出现与否,维护因子极值即可。前后各扫一次。
代码:

1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 const int maxn = 100000+50; 8 const int mmm = 1000000007; 9 struct st{ 10 int posmi; 11 int posmx; 12 int temp; 13 }; 14 st b[20000]; 15 struct ss{ 16 int l; 17 int r; 18 int x; 19 }; 20 ss a[maxn]; 21 int main() 22 { 23 int n; 24 // freopen("1001.in","r",stdin); 25 // freopen("20.txt","w",stdout); 26 while(~scanf("%d",&n)) 27 { 28 memset(b,0,sizeof(b)); 29 memset(a,0,sizeof(a)); 30 for(int i=0;i<n;i++) 31 scanf("%d",&a[i].x); 32 for(int i=0;i<n;i++) 33 { 34 a[i].l=0; 35 a[i].r=n-1; 36 int tt=sqrt(a[i].x); 37 for(int j=1;j<=tt;j++) 38 { 39 if(a[i].x%j==0&&b[j].temp) 40 { 41 if(a[i].x!=j) 42 { 43 if(a[i].l==0) 44 a[i].l=b[j].posmx+1; 45 else 46 a[i].l=max(a[i].l,b[j].posmx+1); 47 } 48 } 49 if(a[i].x%j==0&&b[a[i].x/j].temp) 50 { 51 int kk=a[i].x/j; 52 if(kk!=a[i].x) 53 { 54 if(a[i].l==0) 55 a[i].l=b[kk].posmx+1; 56 else 57 a[i].l=max(a[i].l,b[kk].posmx+1); 58 } 59 } 60 61 } 62 if(b[a[i].x].temp) 63 { 64 if(a[i].l==0) 65 a[i].l=b[a[i].x].posmx+1; 66 else 67 a[i].l=max(a[i].l,b[a[i].x].posmx+1); 68 } 69 if(b[a[i].x].posmx==0) 70 b[a[i].x].posmx = i; 71 else 72 b[a[i].x].posmx=max(b[a[i].x].posmx,i); 73 b[a[i].x].temp=1; 74 } 75 memset(b,0,sizeof(b)); 76 for(int i=n-1;i>=0;i--) 77 { 78 int tt=sqrt(a[i].x); 79 for(int j=1;j<=tt+1;j++) 80 { 81 if(a[i].x%j==0&&b[j].temp) 82 { 83 if(a[i].x!=j) 84 { 85 if(a[i].r==n-1) 86 a[i].r=b[j].posmi-1; 87 else 88 a[i].r=min(a[i].r,b[j].posmi-1); 89 } 90 } 91 if(a[i].x%j==0&&b[a[i].x/j].temp) 92 { int kk=a[i].x/j; 93 if(kk!=a[i].x) 94 { 95 if(a[i].r==n-1) 96 a[i].r=b[kk].posmi-1; 97 else 98 a[i].r=min(a[i].r,b[kk].posmi-1); 99 } 100 } 101 } 102 if(b[a[i].x].temp) 103 { 104 if(a[i].r==n-1) 105 a[i].r=b[a[i].x].posmi-1; 106 else 107 a[i].r=min(a[i].r,b[a[i].x].posmi-1); 108 } 109 if(b[a[i].x].posmi==0) 110 b[a[i].x].posmi = i; 111 else 112 b[a[i].x].posmi=min(b[a[i].x].posmi,i); 113 b[a[i].x].temp=1; 114 } 115 long long int sum=0,k1,k2; 116 for(int i=0;i<n;i++) 117 { 118 // cout<<a[i].l<<" "<<a[i].r<<endl; 119 k1=a[i].r-i+1,k2=i-a[i].l+1; 120 sum=(sum+k1*k2)%mmm; 121 } 122 printf("%I64d\n",sum); 123 } 124 return 0; 125 }
1002.
题意:给定一个n,k,输入n个数,求有多少个区间,满足:该区间内所有数,是否任意两个的差值都小于k。
题解:RMQ+二分。
线段树来做的话,查询时会变成O(n*logn*logn),会超时 = =。所以只能用查询效率为O(1)的RMQ。
代码如下:

1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include<cstring> 5 using namespace std; 6 const int maxn = 100000+50; 7 int maxsum[maxn][20]; 8 int minsum[maxn][20]; 9 int a[maxn]; 10 void RMQ(int num) //预处理->O(nlogn) 11 { 12 for(int i=0;i<num;i++) 13 maxsum[i][0]=minsum[i][0]=a[i]; 14 for(int j =1; j < 20; ++j) 15 for(int i = 0; i < num; ++i) 16 if(i + (1 << j) - 1 <= num) 17 { 18 maxsum[i][j] = max(maxsum[i][j - 1], maxsum[i + (1 << (j - 1))][j - 1]); 19 minsum[i][j] = min(minsum[i][j - 1], minsum[i + (1 << (j - 1))][j - 1]); 20 } 21 } 22 23 int query(int l,int r) 24 { 25 int k=0; 26 while((1<<(k+1))<(r-l+1)) 27 k++; 28 int tt=min(minsum[l][k],minsum[r-(1<<k)+1][k]); 29 int t=max(maxsum[l][k],maxsum[r-(1<<k)+1][k]); 30 return t-tt; 31 } 32 33 int main() 34 { 35 int test; 36 //freopen("1002.in","r",stdin); 37 //freopen("out.txt","w",stdout); 38 cin>>test; 39 int m,k; 40 while(test--) 41 { 42 scanf("%d%d",&m,&k); 43 for(int i=0;i<m;i++) 44 scanf("%d",&a[i]); 45 RMQ(m); 46 int x; 47 long long int sum=0; 48 for(int i=0;i<m;i++) 49 { 50 int l=i,r=m-1; 51 int mid; 52 while(l+1<r) 53 { 54 mid=(l+r)>>1; 55 if(query(i,mid)<k) 56 l=mid; 57 else 58 r=mid; 59 } 60 if(query(i,r)<k) 61 sum+=r-i+1; 62 else 63 sum+=l-i+1; 64 } 65 printf("%I64d\n",sum); 66 } 67 return 0; 68 }