2016百度之星 资格赛ABCDE
看题:http://bestcoder.hdu.edu.cn/contests/contest_show.php?cid=690
Solved | Pro.ID | Title | Author | Source | (AC/Submit)Ratio |
5685 | Problem A | 2016"百度之星" - 资格赛(Astar Round1) | (215/533)40.34% | ||
5686 | Problem B | 2016"百度之星" - 资格赛(Astar Round1) | (150/424)35.38% | ||
5687 | Problem C | 2016"百度之星" - 资格赛(Astar Round1) | (187/532)35.15% | ||
5688 | Problem D | 2016"百度之星" - 资格赛(Astar Round1) | (226/315)71.75% | ||
5689 | Problem E | 2016"百度之星" - 资格赛(Astar Round1) | (36/72)50.00% |
A.题意:定义小写字母组成的字符串的哈希值,为(单个字母的ASCII码减去28)的乘积。给出长度最多为100000的字符串和最多1000次询问,每次询问[L,R]之间的字符串的哈希值。
题解:
有多种做法。
1.逆元 2.线段树 3.分块数组
1.逆元做法:因为每次求区间[L,R]乘积,可以用[1,R]乘([1,L-1]的逆元),就用预处理前缀积、前缀积逆元来搞,O(1)查询。好像代码写起来最简单。
2.线段树、块状数组做法:就做啊。线段树O(log(n))查询
我的是块状数组的,分sqrt大块,预处理大块,O(sqrt(n))查询,不是很推荐。
代码:
1 //#pragma comment(linker, "/STACK:102400000,102400000") 2 #include<cstdio> 3 #include<cmath> 4 #include<iostream> 5 #include<cstring> 6 #include<algorithm> 7 #include<cmath> 8 #include<map> 9 #include<set> 10 #include<stack> 11 #include<queue> 12 using namespace std; 13 14 #define MZ(array) memset(array, 0, sizeof(array)) 15 #define MF1(array) memset(array, -1, sizeof(array)) 16 #define MINF(array) memset(array, 0x3f, sizeof(array)) 17 #define REP(i,n) for(i=0;i<(n);i++) 18 #define FOR(i,x,n) for(i=(x);i<=(n);i++) 19 #define FORD(i,x,y) for(i=(x);i>=(y);i--) 20 #define RD(x) scanf("%d",&x) 21 #define RD2(x,y) scanf("%d%d",&x,&y) 22 #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z) 23 #define WN(x) printf("%d\n",x); 24 #define RE freopen("D.in","r",stdin) 25 #define WE freopen("huzhi.txt","w",stdout) 26 #define MP make_pair 27 #define PB push_back 28 #define PF push_front 29 #define PPF pop_front 30 #define PPB pop_back 31 typedef long long LL; 32 typedef unsigned long long ULL; 33 34 const double PI=acos(-1.0); 35 const double EPS=1e-10; 36 const int MAXN=1111; 37 const int MOD=9973; 38 int n; 39 int a[MAXN],b[MAXN]; 40 char s[111111]; 41 int l; 42 43 int q[111111]; 44 int ql; 45 46 void init() { 47 int i,j; 48 ql=sqrt(l); 49 int qll = l/ql; 50 REP(i,qll) { 51 q[i]=1; 52 int ed = (i+1)*ql - 1; 53 FOR(j,i*ql,ed) { 54 q[i]*=s[j]; 55 q[i]%=MOD; 56 } 57 } 58 } 59 60 int gank(int a,int b) { 61 if(a==b)return s[a]; 62 int sti=ceil(1.0*a/ql), edi=b/ql; 63 int st = sti*ql; 64 int ed = edi*ql; 65 int i; 66 int re=1; 67 if(ed<st) { 68 FOR(i,a,b) { 69 re*=s[i]; 70 re%=MOD; 71 } 72 } else { 73 FOR(i,a,st-1) { 74 re*=s[i]; 75 re%=MOD; 76 } 77 FOR(i,sti,edi-1) { 78 re*=q[i]; 79 re%=MOD; 80 } 81 FOR(i,ed,b) { 82 re*=s[i]; 83 re%=MOD; 84 } 85 } 86 return re; 87 } 88 89 int farm() { 90 int i; 91 l=strlen(s); 92 REP(i,l)s[i]-=28; 93 init(); 94 REP(i,n) { 95 WN(gank(a[i], b[i])); 96 } 97 } 98 99 int main() { 100 int i; 101 while(RD(n)!=EOF) { 102 scanf(" %s",s); 103 REP(i,n) { 104 RD2(a[i],b[i]); 105 a[i]--; 106 b[i]--; 107 } 108 farm(); 109 } 110 return 0; 111 }
B.定义全1序列,其中任意2个1可以组成1个2。给出1的数量(N<=200),求可以组成多少不同的序列。
题解:
找规律,或者推出规律。
设n个1组成的不同序列数量为a[n],可以得知规律:
a[n] = a[n-1] + a[n-2]
相当于n-2的序列后面跟个2,n-1的序列后面跟个1。
注意,从公式可以看出,最后答案大上天,比2^200大,用java的BigInteger搞。
代码:
1 import java.io.BufferedReader; 2 import java.io.IOException; 3 import java.io.InputStreamReader; 4 import java.io.OutputStreamWriter; 5 import java.io.PrintWriter; 6 import java.io.StreamTokenizer; 7 import java.math.BigInteger; 8 9 public class Main { 10 11 private static final int MAXN = 11111; 12 13 private static final StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))); 14 private static final PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out)); 15 16 private static int RD(StreamTokenizer in) throws IOException { 17 in.nextToken(); 18 return (int) in.nval; 19 } 20 21 public static BigInteger gank(int x){ 22 BigInteger[] a = new BigInteger[x+5]; 23 a[1]=BigInteger.ONE; 24 a[2]=BigInteger.ONE.add(BigInteger.ONE); 25 for(int i=3; i<=x; i++){ 26 a[i]=a[i-1].add(a[i-2]); 27 } 28 return a[x]; 29 } 30 31 public static void main(String[] args) throws IOException { 32 while (in.nextToken() != StreamTokenizer.TT_EOF) { 33 int n = (int) in.nval; 34 out.println(gank(n)); 35 // for (int i = 0; i < n; i++) { 36 // int x = RD(in); 37 //// ma = Math.max(ma, x); 38 // out.println(gank(x)); 39 // } 40 41 // out.printf("%s\n", ans); 42 out.flush(); 43 } 44 } 45 46 }
C.题面:
度熊手上有一本神奇的字典,你可以在它里面做如下三个操作:
1、insert : 往神奇字典中插入一个单词
2、delete: 在神奇字典中删除所有前缀等于给定字符串的单词
3、search: 查询是否在神奇字典中有一个字符串的前缀等于给定的字符串
10W个操作,字符串长度不超过30。
题解:
可以看出这是Trie树题,不过有一般Trie树题没有的删除操作。注意删除时找到那个节点,得到通过节点的字符串数x, 然后子树也要处理,到根的路径也要处理。
子树可以删掉,也可以字符串数清零。到根的路径每个点减去x。
代码:
1 //#pragma comment(linker, "/STACK:102400000,102400000") 2 #include<cstdio> 3 #include<cmath> 4 #include<iostream> 5 #include<cstring> 6 #include<algorithm> 7 #include<cmath> 8 #include<map> 9 #include<set> 10 #include<stack> 11 #include<queue> 12 using namespace std; 13 14 #define MZ(array) memset(array, 0, sizeof(array)) 15 #define MF1(array) memset(array, -1, sizeof(array)) 16 #define MINF(array) memset(array, 0x3f, sizeof(array)) 17 #define REP(i,n) for(i=0;i<(n);i++) 18 #define FOR(i,x,n) for(i=(x);i<=(n);i++) 19 #define FORD(i,x,y) for(i=(x);i>=(y);i--) 20 #define RD(x) scanf("%d",&x) 21 #define RD2(x,y) scanf("%d%d",&x,&y) 22 #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z) 23 #define WN(x) printf("%d\n",x); 24 #define RE freopen("D.in","r",stdin) 25 #define WE freopen("huzhi.txt","w",stdout) 26 #define MP make_pair 27 #define PB push_back 28 #define PF push_front 29 #define PPF pop_front 30 #define PPB pop_back 31 typedef long long LL; 32 typedef unsigned long long ULL; 33 34 const double PI=acos(-1.0); 35 const double EPS=1e-10; 36 const int MAXN=111111; 37 const int MAXM=33; 38 39 class Trie{ 40 public: 41 Trie* a[26]; 42 int n; 43 Trie(){ 44 int i; 45 REP(i,26)a[i]=NULL; 46 n=0; 47 } 48 }; 49 50 Trie root; 51 52 inline void ins(char s[MAXM]) { 53 int l=strlen(s); 54 int i,j; 55 Trie *pre = &root; 56 REP(i,l) { 57 int c = s[i] - 'a'; 58 Trie *x = pre->a[c]; 59 if(x==NULL) { 60 pre->a[c] = new Trie(); 61 x = pre->a[c]; 62 } 63 pre->n++; 64 pre=x; 65 } 66 pre->n++; 67 } 68 69 inline Trie* sch(char s[MAXM]) { 70 int l=strlen(s); 71 int i; 72 Trie *x = &root; 73 REP(i,l) { 74 int c = s[i]-'a'; 75 x = x->a[c]; 76 if(x==NULL || x->n<=0)return NULL; 77 } 78 return x; 79 } 80 81 inline void delSon(Trie *x){ 82 int i; 83 if(x->n<=0)return; 84 REP(i,26)if(x->a[i]!=NULL){ 85 delSon(x->a[i]); 86 } 87 // delete(x); 88 x->n=0; 89 } 90 91 inline int del(const int &now, const int &l ,Trie *x, char s[MAXM]) { 92 char c = s[now]-'a'; 93 Trie *w = x->a[c]; 94 if(w==NULL || w->n<=0)return 0; 95 if(now==l-1){ 96 int n = w->n; 97 // x->a[c]=NULL; 98 delSon(w); 99 return n; 100 } 101 w->n -= del(now+1, l, w, s); 102 } 103 104 int main() { 105 int i,n; 106 char c[MAXM],s[MAXM]; 107 RD(n); 108 root = Trie(); 109 REP(i,n) { 110 scanf(" %s %s",c,s); 111 if(c[0]=='i')ins(s); 112 else if(c[0]=='d')del(0,strlen(s),&root,s); 113 else { 114 if(sch(s)!=NULL) puts("Yes"); 115 else puts("No"); 116 } 117 } 118 return 0; 119 }
D.定义某国人名:人名中的任意字母换位置,还是指同一个人。输入10W个人名,对每次输入输出这个人之前出现过多少次。
题解:
对每个人名排序一下再加入map里,随便统计。
代码:
1 //#pragma comment(linker, "/STACK:102400000,102400000") 2 #include<cstdio> 3 #include<cmath> 4 #include<iostream> 5 #include<cstring> 6 #include<algorithm> 7 #include<cmath> 8 #include<map> 9 #include<set> 10 #include<stack> 11 #include<queue> 12 using namespace std; 13 14 #define MZ(array) memset(array, 0, sizeof(array)) 15 #define MF1(array) memset(array, -1, sizeof(array)) 16 #define MINF(array) memset(array, 0x3f, sizeof(array)) 17 #define REP(i,n) for(i=0;i<(n);i++) 18 #define FOR(i,x,n) for(i=(x);i<=(n);i++) 19 #define FORD(i,x,y) for(i=(x);i>=(y);i--) 20 #define RD(x) scanf("%d",&x) 21 #define RD2(x,y) scanf("%d%d",&x,&y) 22 #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z) 23 #define WN(x) printf("%d\n",x); 24 #define RE freopen("D.in","r",stdin) 25 #define WE freopen("huzhi.txt","w",stdout) 26 #define MP make_pair 27 #define PB push_back 28 #define PF push_front 29 #define PPF pop_front 30 #define PPB pop_back 31 typedef long long LL; 32 typedef unsigned long long ULL; 33 34 const double PI=acos(-1.0); 35 const double EPS=1e-10; 36 const int MAXN=1000044; 37 38 int n; 39 map<string,int> q; 40 41 42 int main(){ 43 int i; 44 char s[55]; 45 RD(n); 46 REP(i,n){ 47 scanf(" %s",s); 48 int l = strlen(s); 49 sort(s,s+l); 50 string st = s; 51 WN(q[st]); 52 q[st]++; 53 } 54 return 0; 55 }
E.题面说得超不清楚,根本不可能看懂,所以第一天只有一点点人过这题。我写一下根据Clarify中的参赛者讨论得到的题面:
样例输入: 4 a < 100 c > 99 b > 100 , b == 99 , c < 98 a < 1000, a >= 99 样例输出: unique 1 unique 1 2
其中第一个数N为下面的行数,最多1000。各种变量名最长30。
对于每行输入,输出上面有哪些行与它给出的范围有交集。
例如第二行的c>99,因为第一行没有规定c的范围,相当于c是[-无限,+无限],第二行没有规定a的范围,所以(第一行)交(第二行)不为空。
第三行的b有冲突,是个空集,所以它和谁都不交。
第四行的确和第一行、第二行交。
还有个没说的地方是这个只看整数,a>99, a<100是空集。
题解:
可以看出每行对于每个变量只有一个区间,就暴力模拟就行了。
代码:
1 //#pragma comment(linker, "/STACK:102400000,102400000") 2 #include<cstdio> 3 #include<cmath> 4 #include<iostream> 5 #include<cstring> 6 #include<algorithm> 7 #include<cmath> 8 #include<map> 9 #include<set> 10 #include<stack> 11 #include<queue> 12 using namespace std; 13 14 #define MZ(array) memset(array, 0, sizeof(array)) 15 #define MF1(array) memset(array, -1, sizeof(array)) 16 #define MINF(array) memset(array, 0x3f, sizeof(array)) 17 #define REP(i,n) for(i=0;i<(n);i++) 18 #define FOR(i,x,n) for(i=(x);i<=(n);i++) 19 #define FORD(i,x,y) for(i=(x);i>=(y);i--) 20 #define RD(x) scanf("%d",&x) 21 #define RD2(x,y) scanf("%d%d",&x,&y) 22 #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z) 23 #define WN(x) printf("%d\n",x); 24 #define RE freopen("1.in","r",stdin) 25 #define WE freopen("huzhi.txt","w",stdout) 26 #define MP make_pair 27 #define PB push_back 28 #define PF push_front 29 #define PPF pop_front 30 #define PPB pop_back 31 typedef long long LL; 32 typedef unsigned long long ULL; 33 34 const double PI=acos(-1.0); 35 const double EPS=1e-10; 36 const int MAXN=1111; 37 const int MAXM=33; 38 39 char w[MAXN][MAXM]; 40 int wn; 41 int q[MAXN]; 42 int qn; 43 44 int n; 45 int L[MAXN][MAXM]; 46 int R[MAXN][MAXM]; 47 bool isPig[MAXN]; 48 49 map<string, int>mp; 50 int xn; 51 void add(int k, char xx[MAXM], char oo[MAXM], int yy) { 52 string name = xx; 53 if(mp.find(name)==mp.end())mp[name] = xn++; 54 int x = mp[name]; 55 56 if(oo[0]=='<') { 57 if(oo[1]=='=') R[k][x] = min(R[k][x], yy); 58 else R[k][x] = min(R[k][x], yy - 1); 59 } else if(oo[0]=='>') { 60 if(oo[1]=='=') L[k][x] = max(L[k][x], yy); 61 else L[k][x] = max(L[k][x], yy + 1); 62 } else { 63 L[k][x] = max(L[k][x], yy); 64 R[k][x] = min(R[k][x], yy); 65 } 66 if(L[k][x]>R[k][x])isPig[k]=1; 67 } 68 69 void saveTheEquals() { 70 int i,j,k; 71 mp.clear(); 72 xn=0; 73 MZ(isPig); 74 REP(i,n) REP(j,30) { 75 L[i][j]=-20000; 76 R[i][j]=20000; 77 } 78 i=0; 79 j=0; 80 k=0; 81 while(i<wn) { 82 if(!isPig[k])add(k,w[i],w[i+1],q[j]); 83 j++; 84 if(w[i+2][0]!=',') { 85 k++; 86 i+=2; 87 } else i+=3; 88 } 89 } 90 91 inline bool banana(const int &x,const int &y,const int &k) { 92 int &L1 = L[x][k]; 93 int &R1 = R[x][k]; 94 int &L2 = L[y][k]; 95 int &R2 = R[y][k]; 96 if(L1<=L2 && L2<=R1)return true; 97 if(L2<=L1 && L1<=R2)return true; 98 return false; 99 } 100 101 void farm() { 102 int i,j,k; 103 REP(i,n) { 104 vector<int>v; 105 v.clear(); 106 if(!isPig[i]) { 107 REP(j,i) { 108 bool ok=true; 109 if(isPig[j])continue; 110 REP(k,xn) { 111 if(!banana(i,j,k)) { 112 ok=false; 113 break; 114 } 115 } 116 if(ok) { 117 v.push_back(j+1); 118 } 119 } 120 } 121 if(v.size()==0) { 122 puts("unique"); 123 } else { 124 printf("%d",v[0]); 125 for(j=1; j<v.size(); j++) 126 printf(" %d",v[j]); 127 puts(""); 128 } 129 } 130 } 131 132 int main() { 133 // RE; 134 int i,j; 135 char s[MAXM]; 136 char line[MAXN]; 137 RD(n); 138 wn=0; 139 qn=0; 140 while(scanf(" %s",s)!=EOF) { 141 strcpy(w[wn],s); 142 wn++; 143 if(s[0]!=',') { 144 scanf(" %s %d",w[wn], &q[qn]); 145 wn++; 146 qn++; 147 } 148 } 149 saveTheEquals(); 150 farm(); 151 return 0; 152 }