2015 Multi-University Training 3 多校集训 第三场 部分题解及反思
2015-07-29 11:10
405 查看
昨天打完的第三场,相对而言发挥的还算正常,毕竟弱渣一只,不过有几道简单题都没看,如果放弃那道1010的DP的话还是可以多做两题的,DP依旧是硬伤。
最后做了5道题,勉强挤进第二页。如果能把速度提上去的话应该可以进第一页的。。DP题卡了2个小时不多说。不过赛后看官方题解说DFS就可以了,感觉有点崩溃。
部分题解:
HDU 5316 A.Magician
题意:
给你一个长度不超过10W的数组,10W个询问。询问分为两种操作。
0 X Y 查询X到Y的区间里面的一个和最大的子序列,要求子序列中相邻的数的位置的奇偶性不同。
1 X Y 将数字a[x]修改为Y
题解:
很明显的一道线段树。当然是线段树谁都能看出来。。。
线段树维护四个值,奇数开始偶数结尾的子序列的最大值,奇数开始奇数结尾的子序列的最大值,还有偶数开始奇数结尾和偶数开始偶数结尾。 如果不存在则值记为负Inf(题目要求子序列不能为空)
合并的操作:
奇数开始偶数结尾记为 JO 奇数开始奇数结尾记为JJ 偶数开始偶数结尾记为OO 偶数开始奇数结尾记为OJ
OJ+OJ=OJ
OJ+OO=OO
JO+JO=JO
JO+JJ=JJ
JJ+OO=JO
JJ+OJ=JJ
OO+JO=OO
OO+JJ=OJ
最后选取最大值即可。
HDU 5317 B . RGCDQ
题意:
设F[i]=i的不同的素因子个数,求区间[L,R]里面的最大的gcd(f[i],f[j]),数据最大到100W
题解:
首先nlogn的算法解出每个数的素因子个数(素数筛法)。可以发现,在100W的范围内,每个数的素因子个数不超过7(2*3*5*7*11*13*17*19>100W)。
那么直接枚举最终结果,然后二分查找即可。
比如查找ans=7,那么就找两个不同F[i]=7的在[L,R]的数字。
赛后看别人的方法,好像只用枚举一个数字就可以了..我的方法一次枚举两个数字...额还是太弱。
HDU 5318
C.The Goddess Of The Moon
题意:
给你n个字符串,长度不超过9,如果字符串A有一个长度超过1的前缀和字符串B的后缀相同的话,则A可以接在B后面,问有多少种方法可以接出一个长度为m的字符串,n最多50,m到1e9.
题解:
这题比赛的时候没时间看,赛后Fuei给我讲了一下题意....心里千万草尼马踏过....竟然又漏掉一道简单题TAT。
由于n和字符串长度都很小,所以可以随便暴力一下弄出两个字符串的关系,弄成一张邻接矩阵maze。然后就是快速幂求出maze的(m-1)次方,最后把maze里面所有的数字加起来就好了。
(然而后来做的时候在前面怕超时加了一个剪枝...错误的剪枝...CHA了快一个小时....最后删掉就好了..)
HDU 5319
D.Painter
题意:
一面墙,在上面涂色,从左上到右下的都是R,从右上到左下的都是B,如果既有R又有B,就会显示G。给你一面墙,问至少要涂多少笔。
题解:
水题,n只有50,想怎么暴力怎么暴力。
需要注意的是,给的墙不是n*n的,而是n*m,
m要从输入中得出来。具体看代码。
累了....留坑待填。
最后做了5道题,勉强挤进第二页。如果能把速度提上去的话应该可以进第一页的。。DP题卡了2个小时不多说。不过赛后看官方题解说DFS就可以了,感觉有点崩溃。
部分题解:
HDU 5316 A.Magician
题意:
给你一个长度不超过10W的数组,10W个询问。询问分为两种操作。
0 X Y 查询X到Y的区间里面的一个和最大的子序列,要求子序列中相邻的数的位置的奇偶性不同。
1 X Y 将数字a[x]修改为Y
题解:
很明显的一道线段树。当然是线段树谁都能看出来。。。
线段树维护四个值,奇数开始偶数结尾的子序列的最大值,奇数开始奇数结尾的子序列的最大值,还有偶数开始奇数结尾和偶数开始偶数结尾。 如果不存在则值记为负Inf(题目要求子序列不能为空)
合并的操作:
奇数开始偶数结尾记为 JO 奇数开始奇数结尾记为JJ 偶数开始偶数结尾记为OO 偶数开始奇数结尾记为OJ
OJ+OJ=OJ
OJ+OO=OO
JO+JO=JO
JO+JJ=JJ
JJ+OO=JO
JJ+OJ=JJ
OO+JO=OO
OO+JJ=OJ
最后选取最大值即可。
#include <bits/stdc++.h> using namespace std; int x; int y; const long long dinf=-1e18; const int maxn=100005; long long jon; long long ojn; long long oon; long long jjn; int a[maxn]; long long jo[maxn*4]; long long oj[maxn*4]; long long oo[maxn*4]; long long jj[maxn*4]; long long max(long long a,long long b) { if (a>b) return a; return b; } void build(int l,int r,int o) { if (l==r) { if (l%2)jj[o]=a[l]; else oo[o]=a[l]; return ; } int mid=(l+r)/2; build(l,mid,2*o); build(mid+1,r,2*o+1); jo[o]=max(max(jj[2*o]+oo[2*o+1],jo[2*o]+jo[2*o+1]),max(jo[2*o],jo[2*o+1])); oj[o]=max(max(oo[2*o]+jj[2*o+1],oj[2*o]+oj[2*o+1]),max(oj[2*o],oj[2*o+1])); oo[o]=max(max(oj[2*o]+oo[2*o+1],oo[2*o]+jo[2*o+1]),max(oo[2*o],oo[2*o+1])); jj[o]=max(max(jo[2*o]+jj[2*o+1],jj[2*o]+oj[2*o+1]),max(jj[2*o],jj[2*o+1])); return ; } void add(int l,int r,int o) { if (r<x) return ; if (l>x) return ; if (l==r) { if (l%2) jj[o]=y; else oo[o]=y; return ; } int mid=(l+r)/2; add(l,mid,2*o); add(mid+1,r,2*o+1); jo[o]=max(max(jj[2*o]+oo[2*o+1],jo[2*o]+jo[2*o+1]),max(jo[2*o],jo[2*o+1])); oj[o]=max(max(oo[2*o]+jj[2*o+1],oj[2*o]+oj[2*o+1]),max(oj[2*o],oj[2*o+1])); oo[o]=max(max(oj[2*o]+oo[2*o+1],oo[2*o]+jo[2*o+1]),max(oo[2*o],oo[2*o+1])); jj[o]=max(max(jo[2*o]+jj[2*o+1],jj[2*o]+oj[2*o+1]),max(jj[2*o],jj[2*o+1])); return ; } void query(int l,int r,int o) { if (r<x) return ; if (l>y) return ; if (x<=l&&r<=y) { long long a=jon; long long b=ojn; long long c=oon; long long d=jjn; jon=max(max(d+oo[o],a+jo[o]),max(a,jo[o])); ojn=max(max(c+jj[o],b+oj[o]),max(b,oj[o])); oon=max(max(b+oo[o],c+jo[o]),max(c,oo[o])); jjn=max(max(a+jj[o],d+oj[o]),max(d,jj[o])); return ; } int mid=(l+r)/2; query(l,mid,2*o); query(mid+1,r,2*o+1); return ; } void print(int l,int r,int o) { printf("%d %d %d %lld %lld %lld %lld\n",l,r,o,jo[o],oj[o],oo[o],jj[o]); if (l==r) return ; int mid=(l+r)/2; print(l,mid,2*o); print(mid+1,r,2*o+1); } int main() { int t,n,q,m; int type; scanf("%d",&t); while (t--) { scanf("%d%d",&n,&m); memset(a,0,sizeof(a)); memset(jo,0,sizeof(jo)); memset(oj,0,sizeof(oj)); memset(oo,0,sizeof(oo)); memset(jj,0,sizeof(jj)); for (int i=1;i<=n;i++) scanf("%d",&a[i]); for (int i=1;i<maxn*4;i++) { jo[i]=dinf; oj[i]=dinf; oo[i]=dinf; jj[i]=dinf; } build(1,n,1); while (m--) { scanf("%d%d%d",&type,&x,&y); if (!type) { jon=ojn=oon=jjn=dinf; query(1,n,1); cout<<max(max(jon,ojn),max(oon,jjn))<<endl; } else add(1,n,1); } } return 0; }
HDU 5317 B . RGCDQ
题意:
设F[i]=i的不同的素因子个数,求区间[L,R]里面的最大的gcd(f[i],f[j]),数据最大到100W
题解:
首先nlogn的算法解出每个数的素因子个数(素数筛法)。可以发现,在100W的范围内,每个数的素因子个数不超过7(2*3*5*7*11*13*17*19>100W)。
那么直接枚举最终结果,然后二分查找即可。
比如查找ans=7,那么就找两个不同F[i]=7的在[L,R]的数字。
赛后看别人的方法,好像只用枚举一个数字就可以了..我的方法一次枚举两个数字...额还是太弱。
#include <bits/stdc++.h> using namespace std; vector <int> v[10]; int f[1000005]; int x,y; int find(int t) { int ans=-1; int l=0; int r=v[t].size()-1; while (l<=r) { int mid=(l+r)/2; if (v[t][mid]>=x) { ans=mid; r=mid-1; } else l=mid+1; } return ans; } int gcd(int a,int b) { if (!b) return a; return gcd(b,a%b); } int main() { memset(f,0,sizeof(f)); for (int i=2;i<=1000000;i++) { if (f[i]==0) { for (int j=i;j<=1000000;j+=i) { f[j]++; } } } for (int i=1;i<=7;i++) v[i].clear(); for (int i=2;i<=1000000;i++) v[f[i]].push_back(i); int t,ans; scanf("%d",&t); while (t--) { scanf("%d%d",&x,&y); ans=1; for (int i=2;i<=7;i++) { int t1=find(i); if (t1==-1) continue; if (v[i][t1]>y) continue; for (int j=2;j<=i;j++) { if (ans>=gcd(i,j)) continue; int t2=find(j); if (t2==-1) continue; if (i==j) t2++; if (t2>=v[j].size()||v[j][t2]>y) continue; ans=gcd(i,j); } } printf("%d\n",ans); } return 0; }
HDU 5318
C.The Goddess Of The Moon
题意:
给你n个字符串,长度不超过9,如果字符串A有一个长度超过1的前缀和字符串B的后缀相同的话,则A可以接在B后面,问有多少种方法可以接出一个长度为m的字符串,n最多50,m到1e9.
题解:
这题比赛的时候没时间看,赛后Fuei给我讲了一下题意....心里千万草尼马踏过....竟然又漏掉一道简单题TAT。
由于n和字符串长度都很小,所以可以随便暴力一下弄出两个字符串的关系,弄成一张邻接矩阵maze。然后就是快速幂求出maze的(m-1)次方,最后把maze里面所有的数字加起来就好了。
(然而后来做的时候在前面怕超时加了一个剪枝...错误的剪枝...CHA了快一个小时....最后删掉就好了..)
#include <bits/stdc++.h> using namespace std; const long long mod=1e9+7; long long maze[55][55]; long long a[55][55]; long long b[55][55]; vector<string>s; int n; bool check(int x,int y,int l) { int len=s[x].length(); for (int i=0;i<l;i++) { if (s[x][len-l+i]!=s[y][i]) return false; } return true; } bool comp(int x,int y) { int len=min(s[x].length(),s[y].length()); for (int i=2;i<=len;i++) { if (check(x,y,i)) return true; } return false; } void Init() { memset(a,0,sizeof(a)); for (int i=1;i<=n;i++) a[i][i]=1; } void chen1() { memset(b,0,sizeof(b)); for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) { for (int k=1;k<=n;k++) { b[i][j]+=a[i][k]*maze[k][j]; b[i][j]%=mod; } } } for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) { a[i][j]=b[i][j]; } } return ; } void chen2() { memset(b,0,sizeof(b)); for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) { for (int k=1;k<=n;k++) { b[i][j]+=maze[i][k]*maze[k][j]; b[i][j]%=mod; } } } for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) { maze[i][j]=b[i][j]; } } return ; } void qpow(int x) { Init(); x--; while (x) { if (x%2) chen1(); chen2(); x>>=1; } return ; } int main() { int t,m; long long ans; string str; scanf("%d",&t); while (t--) { scanf("%d%d",&n,&m); s.clear(); for (int i=1;i<=n;i++) { cin>>str; bool f=false; for (int j=0;j<s.size();j++) { if (s[j]==str) { f=true; break; } } if (!f) s.push_back(str); } n=s.size(); memset(maze,0,sizeof(maze)); for (int i=0;i<n;i++) { for (int j=0;j<n;j++) { if (comp(i,j)) maze[i+1][j+1]=1; } } // for (int i=1;i<=n;i++) // { // for (int j=1;j<=n;j++) // { // printf("% 4d ",maze[i][j]); // } // printf("\n"); // } qpow(m); ans=0; for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) { ans+=a[i][j]%mod; ans%=mod; } } cout<<ans<<endl; } return 0; }
HDU 5319
D.Painter
题意:
一面墙,在上面涂色,从左上到右下的都是R,从右上到左下的都是B,如果既有R又有B,就会显示G。给你一面墙,问至少要涂多少笔。
题解:
水题,n只有50,想怎么暴力怎么暴力。
需要注意的是,给的墙不是n*n的,而是n*m,
m要从输入中得出来。具体看代码。
#include <bits/stdc++.h> using namespace std; char s[105][105]; int n,m; void DW1(int x,int y) { while (1) { if (s[x][y]=='R') s[x][y]='.'; else if (s[x][y]=='G') s[x][y]='B'; else return ; x++; y++; if (x>=n||y>=m) return ; } return ; } void DW2(int x,int y) { while (1) { if (s[x][y]=='B') s[x][y]='.'; else return ; x++; y--; if (x>=n||y<0) return ; } } int main() { int t; int ans; scanf("%d",&t); while (t--) { scanf("%d",&n); for (int i=0;i<n;i++)scanf("%s",s[i]); m=strlen(s[0]); ans=0; for (int i=0;i<n;i++) { for (int j=0;j<m;j++) { if (s[i][j]=='R'||s[i][j]=='G') { DW1(i,j); ans++; } } } for (int i=0;i<n;i++) { for (int j=0;j<m;j++) { if (s[i][j]=='B') { ans++; DW2(i,j); } } } printf("%d\n",ans); } return 0; }
累了....留坑待填。
相关文章推荐
- [模拟] 多校联合第三场 painter HDU 5319
- 2015 Multi-University Training Contest 3 1004
- hdu5319(2015多校3)--Painter(暴力,,,)
- async & await 的前世今生(Updated)
- hdu 5319 Painter 2015 Multi-University Training Contest 3
- SVN svnserve.conf: Option expected 的解决方法 以及 Authorization failed 的解决方法
- HDU-1867-A + B for you again
- 关于出现( linker command failed with exit code 1)错误总结
- 2015 Multi-University Training Contest 3 1002 RGCDQ(hdu5317)
- ZOJ 3450 Doraemon's Railgun (DP·分组背包)
- C++使用localtime函数需要注意的地方http://blog.csdn.net/shellching/article/details/8114266
- zoj 3450Doraemon's Railgun
- HDU 5326 Work 并查集 (2015 Multi-University Training Contest 3 2015多校联合)
- HDU 5319 Painter (2015 Multi-University Training Contest 3 2015多校联合)
- STL中的模板类pair 和map http://blog.csdn.net/calvin_zcx/article/details/6072286
- hdu 5317 RGCDQ 2015 Multi-University Training Contest 3
- 线程安全C/C++ http://blog.csdn.net/huangxy10/article/details/8068653
- mysql_num_rows()的作用的功能!!! http://zhidao.baidu.com/link?url=E-LmBdz-E5ff5PKfiXucFY-wWBLV4_vt6Cmg2i4k
- 模拟+思维 HDOJ 5319 Painter
- 多校3 1004 Painter