2017-3-5 周考解题报告

1. permut

1.1 题目描述

求由 1 到 n 一共 n 个数字组成的所有排列中,逆序对个数为 k 的有多少个。

1.2 输入格式

第一行是一个整数数 T,为数据组数。

以下 T 行,每行两个整数 n,k,意义如题目所述。

1.3 输出格式

对每组数据输出答案对 10000 取模后的结果。

1.4 Sample Input

1

4 1

1.5 Sample Output

3

1.6 数据范围及约定

对于30% 的数据,满足n≤12

对于所有数据,满足n≤1000, k≤1000,T≤10

1.7 思路

刚开始拿到题目时,内心OS:woc 这绝对是全卷最难的一道题了(做毕克的题做出心理阴影了)。不过仔细读题之后发现这道题其实是个简单的 DP 逻辑递推题。

假设 f[i,k] 是 1...i 的全排列中逆序对为k的情况个数。相应的排列可以从部分 i-1 的排列中插入 i 转换而来,因为 i 是绝对大于 1...(i-1) 的任意一个数的。因此插入 i 这个行为所添加的逆序对个数直接与插入位置相关。这样的话转移方程就很好出来了。

f[i,j]=f[i,j-1]+f[i-1,j] (j≤i)

f[i,j]=f[i,j-1]+f[i-1,j]-f[i-1,j-i] (j>i)

(然而我的代码里并不是完全按这方程来的)

1.8 代码

 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <string>
 6 #include <sstream>
 7 #include <algorithm>
 8 #include <cmath>
 9 #include <stack>
10 #include <queue>
11 #include <list>
12 
13 using namespace std;
14 
15 const int mod=10000;
16 int T;
17 int n[15],k[15];
18 int f[1100][1100];
19 int ls[1100];
20 int mn,mk;
21 
22 int GetSum(int x,int y){
23     if(x-y<0) return ls[x]%mod;
24     return (ls[x]-ls[x-y]+2*mod)%mod;
25 }
26 
27 int main(){
28     freopen("permut.in","r",stdin);
29     freopen("permut.out","w",stdout);
30     scanf("%d",&T);
31     for(int i=0;i<T;i++){
32         scanf("%d%d",&n[i],&k[i]);
33         mn=max(mn,n[i]); mk=max(mk,k[i]);
34     }
35     for(int i=1;i<=mn;i++){
36         if(i==1) f[i][0]=1;
37         else for(int j=0;j<=mk;j++)
38                 f[i][j]=GetSum(j,i);
39         for(int j=0;j<=mk;j++){
40             if(j==0) ls[j]=f[i][j]%mod;
41             else ls[j]=(f[i][j]+ls[j-1])%mod;
42         }
43     }
44     for(int i=0;i<T;i++) printf("%d\n",f[n[i]][k[i]]);
45     fclose(stdin);
46     fclose(stdout);
47     return 0;
48 }

 

2. beautiful

2.1 题目描述

一个长度为 n 的序列,对于每个位置 i 的数 ai 都有一个优美值,其定义是:找到序列中最长的一段 [l,r],满足l≤i≤r,且 [l,r] 中位数为 ai(我们比较序列中两个位置的数的大小时,以数值为第一关键字,下标为第二关键字比较。这样的话 [l,r] 的长度只有可能是奇数),r-l+1 就是 i 的优美值。

接下来有 Q 个询问,每个询问 [l,r] 表示查询区间 [l,r] 内优美值的最大值。

2.2 输入格式

第一行输入 n 接下来 n 个整数,代表 ai接下来 Q,代表有 Q 个区间接下来 Q 行,每行两个整数 l,r (l≤r),表示区间的左右端点。

2.3 输出格式

对于每个区间的询问,输出答案。

2.4 Sample Input

8

16 19 7 8 9 11 20 16

8

3 8

1 4

2 3

1 1

5 5

1 2

2 8

7 8

2.5 Sample Output

7

3

1

3

5

3

7

3

2.6 数据范围与约定

对于 30% 的数据,满足 n,Q≤50

对于 70% 的数据,满足 n,Q≤2000

对于所有数据,满足n≤2000, Q≤100000,ai≤200

2.7 思路

做题时想也没想就去写了Splay(还写RE了!),后来看了题解才发现直接n2扫一遍+计数就可以了。然后就是裸的RMQ了!

RMQ部分随便写就是了,想用 ST 表的用 ST 表,想用线段树的就用线段树,反正我用的是直接记录 max 值。

2.8 代码

 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <string>
 6 #include <sstream>
 7 #include <algorithm>
 8 #include <cmath>
 9 #include <stack>
10 #include <queue>
11 #include <list>
12 #include <set>
13 
14 using namespace std;
15 
16 int n,seq[2200];
17 int a[2200],Q;
18 int l[2200*2],r[2200*2];
19 
20 int main(){
21     freopen("beautiful.in","r",stdin);
22     freopen("beautiful.out","w",stdout);
23     scanf("%d",&n);
24     for(int i=1;i<=n;i++){
25         scanf("%d",&seq[i]);
26     }
27     for(int i=1;i<=n;i++){
28         memset(l,255,sizeof(l)); l[n]=0;
29         memset(r,255,sizeof(r)); r[n]=0;
30         int cnt=0;
31         for(int j=i+1;j<=n;j++){
32             if(seq[j]>=seq[i]) cnt++;
33             if(seq[j]<seq[i]) cnt--;
34             r[n+cnt]=j-i;
35         }
36         cnt=0;
37         for(int j=i-1;j>=1;j--){
38             if(seq[j]>seq[i]) cnt++;
39             if(seq[j]<=seq[i]) cnt--;
40             l[n+cnt]=i-j;
41         }
42         for(int j=1-i;j<=i-1;j++)
43             if(l[n+j]>=0&&r[n-j]>=0)
44                 a[i]=max(a[i],l[n+j]+1+r[n-j]);
45     }
46     scanf("%d",&Q);
47     while(Q--){
48         int l,r;
49         scanf("%d%d",&l,&r);
50         int ans=0;
51         for(int i=l;i<=r;i++) ans=max(ans,a[i]);
52         printf("%d\n",ans);
53     }
54     fclose(stdin);
55     fclose(stdout);
56     return 0;
57 }

 

3. subset

作者太懒了,就放个链接吧:

http://blog.csdn.net/Lifel/article/details/60574232

posted @ 2017-03-06 21:36  VKorpela  阅读(348)  评论(0编辑  收藏  举报
知识共享许可协议
爱与包容记心中 · 友谊魔法永流传
加密文章的密码是最棒的小马名字(没有空格)