http://acm.hust.edu.cn/vjudge/contest/130363#overview
比赛
A 题意:每个题目有难度1-10, 可能被泄露, 以及是否通过. 求多少对可疑记录, 可疑记录对定义为 泄露的题目通过了,却没通过难度低,没泄露的题目.
解法: on统计每个难度1-10有多少题满足没泄露且没通过, 然后再on遍历,对每个泄露且通过的题目, 所有难度比他低的记录都能构成一对答案,累加.
1 //#define txtout 2 //#define debug 3 #include<bits/stdc++.h> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 typedef long long LL; 7 const double pi=acos(-1.0); 8 const double eps=1e-8; 9 const int inf=0x3f3f3f3f; 10 const int M=1e5+10; 11 int n; 12 struct G{ 13 int d,flag; 14 char c[4]; 15 }g[M]; 16 LL sum[16]; 17 void init(){ 18 mt(sum,0); 19 for(int i=0;i<n;i++){ 20 if(!g[i].flag&&g[i].c[0]=='i'){ 21 sum[g[i].d]++; 22 } 23 } 24 for(int i=2;i<=10;i++){ 25 sum[i]+=sum[i-1]; 26 } 27 } 28 LL solve(){ 29 init(); 30 LL answer=0; 31 for(int i=0;i<n;i++){ 32 if(g[i].flag&&g[i].c[0]=='c'){ 33 answer+=sum[g[i].d-1]; 34 } 35 } 36 return answer; 37 } 38 int main(){ 39 #ifdef txtout 40 freopen("in.txt","r",stdin); 41 freopen("out.txt","w",stdout); 42 #endif // txtout 43 int t; 44 scanf("%d",&t); 45 while(t--){ 46 scanf("%d",&n); 47 for(int i=0;i<n;i++){ 48 scanf("%d%d%s",&g[i].d,&g[i].flag,g[i].c); 49 } 50 printf("%lld\n",solve()); 51 } 52 return 0; 53 }
B 题意:给月份和该月第一天是星期几,问该月有几个星期五和星期六。
解法:得到月份和星期,然后遍历每一天统计。
1 //#define txtout 2 //#define debug 3 #include<bits/stdc++.h> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 typedef long long LL; 7 const double pi=acos(-1.0); 8 const double eps=1e-8; 9 const int inf=0x3f3f3f3f; 10 const int M=1e5+10; 11 char month[32][32]={"JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"}; 12 int day[32]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 ,31}; 13 char weekday[32][32]={"SUN","MON","TUE","WED","THU","FRI","SAT"}; 14 char a[M]; 15 char b[M]; 16 int getMonth(){ 17 for(int i=0;i<12;i++){ 18 if(!strcmp(a,month[i])) return i; 19 } 20 return -1; 21 } 22 int getWeek(){ 23 for(int i=0;i<7;i++){ 24 if(!strcmp(b,weekday[i])) return i; 25 } 26 return -1; 27 } 28 int solve(){ 29 int m=getMonth(); 30 int w=getWeek(); 31 int d=day[m]; 32 int sum=0; 33 for(int i=1;i<=d;i++){ 34 if(w==5||w==6){ 35 sum++; 36 } 37 w=(w+1)%7; 38 } 39 return sum; 40 } 41 int main(){ 42 #ifdef txtout 43 freopen("in.txt","r",stdin); 44 freopen("out.txt","w",stdout); 45 #endif // txtout 46 int t; 47 scanf("%d",&t); 48 while(t--){ 49 scanf("%s%s",a,b); 50 printf("%d\n",solve()); 51 } 52 return 0; 53 }
C 等待补充。
D 题意:给一个字符串,问构造一个与其长度一样的串,最长公共子序列的长度最短为多少。
解法: 贪心的选取一个原串出现次数最少的字符,全用这个字符构成一个串,最长公共子序列的长度就是这个字符在原串中出现次数。
1 //#define txtout 2 //#define debug 3 #include<bits/stdc++.h> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 typedef long long LL; 7 const double pi=acos(-1.0); 8 const double eps=1e-8; 9 const int inf=0x3f3f3f3f; 10 const int M=1e5+10; 11 char a[M]; 12 int sum[32]; 13 int solve(){ 14 mt(sum,0); 15 for(int i=0;a[i];i++){ 16 sum[a[i]-'a']++; 17 } 18 int answer=inf; 19 for(int i=0;i<26;i++){ 20 answer=min(answer,sum[i]); 21 } 22 return answer; 23 } 24 int main(){ 25 #ifdef txtout 26 freopen("in.txt","r",stdin); 27 freopen("out.txt","w",stdout); 28 #endif // txtout 29 int t,cas=1; 30 scanf("%d",&t); 31 while(t--){ 32 scanf("%s",a); 33 printf("Case %d: %d\n",cas++,solve()); 34 } 35 return 0; 36 }
E 题意:输入n,求2-n所有F(i)的和, F[i]是 i 所有因子的和。
解法:枚举每个数,其倍数的位置都加上这个数,这个的复杂度是 n/1+n/2+n/3+...+n/n= n*(1/1+1/2+1/3+1/4) ~= n*ln(n). 调和级数。然后再求个前缀和,查询O1。
1 //#define txtout 2 //#define debug 3 #include<bits/stdc++.h> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 typedef long long LL; 7 const double pi=acos(-1.0); 8 const double eps=1e-8; 9 const int inf=0x3f3f3f3f; 10 const int M=2e7+10; 11 int n; 12 LL a[M]; 13 void init(){ 14 for(int i=2;i<M;i++){ 15 a[i]=1; 16 } 17 for(int i=2;i<M;i++){ 18 for(int j=i;j<M;j+=i){ 19 a[j]+=i; 20 } 21 } 22 for(int i=3;i<M;i++){ 23 a[i]+=a[i-1]; 24 } 25 } 26 int main(){ 27 #ifdef txtout 28 freopen("in.txt","r",stdin); 29 freopen("out.txt","w",stdout); 30 #endif // txtout 31 init(); 32 while(~scanf("%d",&n),n){ 33 printf("%lld\n",a[n]); 34 } 35 return 0; 36 }
F 题意: 从n*m的矩阵中,选取一个平行于边界的子矩阵, 子矩阵的值表示高度, 他们会选一个点开party, 这个点满足所有点到这个点的距离和最小,如果多个点满足条件,会选取高度最高的. 选出这个点以后, 和查询的h比较,如果这个点的高度<h,party取消. 查询h, 对每个h , 输出能选出的最大面积的子矩形, 满足上述约束.
解法: 暴力, 枚举出一个子矩阵, n^4, 判断是否满足约束,满足就更新答案。 判断, 暴力的话枚举找开party的点,依次和所有点做差, 得到距离和最小的,相同选高度最高的, n^4, 然后判断 是否<h.
T*Q*n^8。
第一步优化:优化判断,将所有子矩阵的点排序,对于最大Hn的和最小H1的两个点来说,选取任意一个点Hi,他们两个的距离和 Hn-Hi + Hi-H1 都等于他们的距离 Hn - H1 ,那么这两个元素就可以消去了,明显贪心的选取中间的会更好, 如果选两个元素之外的, 距离明显增加。 以此类推, 相当于求中位数的过程。 当n 为奇数时, 选取的点 唯一, 当n 为偶数时, 根据题意选取 h大的。
所以 , 对于查询 h 来说, 一个子矩阵是否满足约束, 条件转化为, 该子矩阵中位数(偶数时是中间两个数较大的那个数,不是数学定义里的中位数)要 〉=h。再进一步转化,子矩阵中〉=h的个数要超过一半。
当n为偶数时,(大于等于h的个数)要〉=n/2。 当n为奇数的时候(大于等于h的个数)要〉=n/2+1.
此时,对于一个查询 h ,可以n^2预处理, 将〉=h的点设为1,将<h 的设为0。然后n^2预处理出sum[x][y],表示 (1,1)到(x,y)子矩阵的和。 然后n^4枚举子矩阵,O1判断,判断方法就是求该子矩阵1的个数是否》=总个数/2, 求任意一个子矩阵的和, 可以容斥原理, sum[x2][y2] - sum[x2][y1-1] -sum[x1-1][y2] + sum[x1-1][y1-1];
目前复杂度只剩枚举子矩阵, T*Q*n^4。 但还是超时。 还要优化 。
先做一个预处理,〉=h设置为1,<h设置为-1 , 上述约束转化为子矩阵的和>=0。
首先n^2枚举出子矩阵的左边界和右边界,然后用一维数组 s[i] 记录 第 i 行在界内的和。 枚举行on, 用前缀和o1求, 这里的复杂度是 on3。
问题转化为了, 在s这个一维数组中,找到一段连续的子段,在满足子段和>=0的情况下,使得子段尽可能长。因为这样面积就大了。
处理这个问题,n2枚举起点终点,用前缀和o1判合法, 是可行的, 但是复杂度就回到 n4了。
设起点x+1,终点y, 约束就是 S[y]-S[x]>=0 , 子段长度就是 y - x,
我们考虑处理出单调序列,然后双指针。
开始时序列为空,从前往后枚举S[i] , 作为 S[x], 当序列为空时,将s[ i ]加入序列, 当序列不为空时, 只有s[i] 的值小于序列最后一个元素的值,才加入序列尾部。
原因是,我们希望x越小越好, sx也越小越好,这样更有可能满足条件,也更有可能更新答案, 那么当来一个元素 , 我们尝试用它作为sx时, 因为我们从前往后枚举, 所以x显然已经比之前的大了,只有sx比之前的小,才有可能找到更好的解,否则之前的解一定更好。
经过这次on,我们处理出了一个sx序列,序号x递增,值sx递减的序列。
同理,我们从后往前枚举si, 作为sy。 当序列为空时, 加入, 当不为空时, 只有当 sy的值大于序列最后一个元素的值,才加入序列尾部。
原因是,我们希望y越大越好, sy也越小越好,这样更有可能满足条件,也更有可能更新答案, 那么当来一个元素 , 我们尝试用它作为sy时, 因为我们从后往前枚举, 所以y显然已经比之前的小了,只有sy比之前的大,才有可能找到更好的解,否则之前的解一定更好。 (多目标优化的非支配解集,这个序列实际上)
经过这次on,我们处理出了一个sy序列,序号y递减,值sy递增的序列。
下面我们用两个指针来枚举解,复杂度2 n。
i 枚举sy中每一个元素, j开始时停在sx的尾部。
对于每个i , j一开始在sx 最小的地方,
如果满足,就更新答案,j--。 因为当前满足了, 所以我们尝试让sx 增大一点, 这样x就减少了,如果还〉=0,那还能进一步更新答案,如果不合法了,说明我们已经枚举完 i 结尾的所有情况了。
当i++的时候 j停在原地, 所以能2n, 停在原地是对的的原因是, i++导致sy增大, 那么 sx可能不变,也可能增大,不会去减小,减小使得x增加,对答案没有好处。
单调的两个指针 使得这步复杂度on, 整体TQn3
1 //#define txtout 2 //#define debug 3 #include<bits/stdc++.h> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 typedef long long LL; 7 const double pi=acos(-1.0); 8 const double eps=1e-8; 9 const int inf=0x3f3f3f3f; 10 const int M=1e3+10; 11 int n,m,lq; 12 int a[M][M]; 13 int b[M][M]; 14 int sum[M][M]; 15 int q[M]; 16 int answer[M]; 17 int buffer[M]; 18 typedef pair<int,int> pii; 19 pii tail[M],head[M]; 20 void init(int h){ 21 for(int i=0;i<n;i++){ 22 for(int j=0;j<m;j++){ 23 b[i][j]=1; 24 if(a[i][j]<h){ 25 b[i][j]=-1; 26 } 27 sum[i][j]=b[i][j]; 28 if(j){ 29 sum[i][j]+=sum[i][j-1]; 30 } 31 } 32 } 33 } 34 int get_buffer(){ 35 for(int i=1;i<n;i++){ 36 buffer[i]+=buffer[i-1]; 37 } 38 if(buffer[n-1]>=0) return n; 39 int answer=0; 40 int len_tail=0; 41 for(int i=n-1;i>=0;i--){ 42 if(buffer[i]>=0){ 43 answer=max(answer,i+1); 44 } 45 int s=len_tail; 46 if(s==0){ 47 tail[len_tail++]=make_pair(buffer[i],i); 48 continue; 49 } 50 if(buffer[i]>tail[s-1].first){ 51 tail[len_tail++]=make_pair(buffer[i],i); 52 } 53 } 54 int len_head=0; 55 for(int i=0;i<n;i++){ 56 int s=len_head; 57 if(s==0){ 58 head[len_head++]=make_pair(buffer[i],i); 59 continue; 60 } 61 if(buffer[i]<head[s-1].first){ 62 head[len_head++]=make_pair(buffer[i],i); 63 } 64 } 65 for(int i=0,j=len_head-1;i<len_tail&&j>=0;i++){ 66 if(tail[i].second<=answer) break; 67 while(j>=0&&tail[i].first-head[j].first>=0){ 68 answer=max(answer,tail[i].second-head[j].second); 69 j--; 70 } 71 } 72 return answer; 73 } 74 int get(int h){ 75 init(h); 76 int answer=0; 77 for(int x=0;x<m;x++){ 78 for(int y=x;y<m;y++){ 79 if(answer>=(y-x+1)*n) continue; 80 for(int i=0;i<n;i++){ 81 int value=sum[i][y]; 82 if(x){ 83 value-=sum[i][x-1]; 84 } 85 buffer[i]=value; 86 } 87 answer=max(answer,(y-x+1)*get_buffer()); 88 } 89 } 90 return answer; 91 } 92 void solve(){ 93 for(int i=0;i<lq;i++){ 94 answer[i]=get(q[i]); 95 } 96 } 97 int main(){ 98 #ifdef txtout 99 freopen("in.txt","r",stdin); 100 freopen("out.txt","w",stdout); 101 #endif // txtout 102 int t,cas=1; 103 scanf("%d",&t); 104 while(t--){ 105 scanf("%d%d",&n,&m); 106 for(int i=0;i<n;i++){ 107 for(int j=0;j<m;j++){ 108 scanf("%d",&a[i][j]); 109 } 110 } 111 scanf("%d",&lq); 112 for(int i=0;i<lq;i++){ 113 scanf("%d",&q[i]); 114 } 115 solve(); 116 printf("Case %d:\n",cas++); 117 for(int i=0;i<lq;i++){ 118 printf("%d\n",answer[i]); 119 } 120 } 121 return 0; 122 }
end