2015 Multi-University Training Contest 7
Contest Type : Private Contest Status : Ended
Current Server Time : 2015-08-11 17:47:07
Solved | Pro.ID | Title | Ratio(Accepted / Submitted) |
1001 | Game On the Tree | 4.44%(2/45) | |
1002 | Tree Maker | 18.75%(21/112) | |
1003 | Hotaru's problem | 10.60%(160/1509) | |
1004 | Segment Game | 13.07%(52/398) | |
1005 | The shortest problem | 26.38%(607/2301) | |
1006 | Tetris | 30.34%(44/145) | |
1007 | Gray code | 31.25%(456/1459) | |
1008 | Convex Polygon | 18.18%(4/22) | |
1009 | Root | 3.41%(7/205) | |
1010 | Leader in Tree Land | 28.74%(50/174) | |
1011 | Mahjong tree | 19.25%(257/1335) |
Pro.ID | Title | Author | Source | (AC/Submit)Ratio |
5369 | Game On the Tree | 2015 Multi-University Training Contest 7 | (12/54)22.22% | |
5370 | Tree Maker | 2015 Multi-University Training Contest 7 | (46/118)38.98% | |
5371 | Hotaru's problem | 2015 Multi-University Training Contest 7 | (593/1653)35.87% | |
5372 | Segment Game | 2015 Multi-University Training Contest 7 | (270/965)27.98% | |
5373 | The shortest problem | 2015 Multi-University Training Contest 7 | (481/948)50.74% | |
5374 | Tetris | 2015 Multi-University Training Contest 7 | (97/217)44.70% | |
5375 | Gray code | 2015 Multi-University Training Contest 7 | (361/612)58.99% | |
5376 | Convex Polygon | 2015 Multi-University Training Contest 7 | (22/70)31.43% | |
5377 | Root | 2015 Multi-University Training Contest 7 | (31/102)30.39% | |
5378 | Leader in Tree Land | 2015 Multi-University Training Contest 7 | (133/351)37.89% | |
5379 | Mahjong tree | 2015 Multi-University Training Contest 7 | (341/1114)30.61% |
HDU5371
给一个长度为n的序列,求最长的连续子序列长度。符合:
可以分成3部分 ,第一部分与第三部分一样,第一部分与第二部分互为转置。
如2 3 4 4 3 2 2 3 4
用manacher算法O(n)时间算出以s[i]和s[i+1]为中心的回文串的半径f[i],只要在f[i]的半径范围[i-f[i],i+f[i]-1]内有f[j]>|j-i|就说明存在符合要求的串,遍历求最大值即可
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int s[220220]; int p[220220]; int f[220220]; int main() { int T; scanf("%d",&T); for(int ca=1;ca<=T;ca++) { int len; scanf("%d",&len); for(int i=0;i<len;i++) { s[i*2]=-1; scanf("%d",&s[i*2+1]); } len*=2; s[len]=-1; p[0]=1; p[1]=2; int maxlen=1; int id=1; for(int i=2;i<=len;i++) { if(i>maxlen) { int k=1; while(i-k>=0&&i+k<=len&&s[i-k]==s[i+k])k++; p[i]=k; maxlen=min(p[i]+i-1,len); id=i; } else { if((2*id-i)-p[2*id-i] != id-p[id]) p[i]=min(p[2*id-i],maxlen-i+1); else { int k=p[2*id-i]; while(i-k>=0&&i+k<=len&&s[i-k]==s[i+k])k++; p[i]=k; maxlen=min(p[i]+i-1,len); id=i; } } } for(int i=0;i<=len;i+=2) { f[i/2]=(p[i]-1)/2; } int ans=0; len/=2; for(int i=0;i<len;i++) { for(int j=ans+1;j<=f[i];j++) { if(f[i+j]>=j)ans=max(ans,j); } } printf("Case #%d: %d\n",ca,ans*3); } return 0; }
HDU5372
有一个数轴,每次往数轴上放一个线段[a,b]或者删除一个线段(每个线段独立)(id),在放前询问[a,a+i]内有多少完整的线段,即之前放的线段有多少是完全在[a,b]的范围内的
[a,b]中b=a+ind,ind为放线段的个数(不包括删除) , id为第id个放入的线段。
用两个树状数组分别维护 <=a ,<=b 的个数,询问时求出左边大于等于当前左端点的线段数目和右边大于当前右端点线段数目,求差即可。
数据需要离散化
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define low(x) (x&(-x)) #define maxn 400040 struct ss { int op,a,b; }arr[maxn/2],add[maxn/2]; int cleft[maxn],cright[maxn]; int s[maxn]; int addleft(int i,int val) { while(i<maxn) { cleft[i]+=val; i+=low(i); } } int getleft(int i) { int sum=0; while(i>0) { sum+=cleft[i]; i-=low(i); } return sum; } int addright(int i,int val) { while(i<maxn) { cright[i]+=val; i+=low(i); } } int getright(int i) { int sum=0; while(i>0) { sum+=cright[i]; i-=low(i); } return sum; } int main() { int n; int ca=1; while(~scanf("%d",&n)) { memset(cleft,0,sizeof(cleft)); memset(cright,0,sizeof(cright)); int ind=0; int ad=0; for(int i=0;i<n;i++) { scanf("%d%d",&arr[i].op,&arr[i].a); arr[i].b=arr[i].a+ad+1; s[ind++]=arr[i].a; s[ind++]=arr[i].b; if(!arr[i].op) { add[ad++]=arr[i]; } } sort(s,s+ind);//paixu ind=unique(s,s+ind)-s;//quchong printf("Case #%d:\n",ca++); for(int i=0;i<n;i++) { if(!arr[i].op){ int a=lower_bound(s,s+ind,arr[i].a)-s+1;//lisan int b=lower_bound(s,s+ind,arr[i].b)-s+1; // printf("add: %d %d %d\n",arr[i].op,a,b); int left=getleft(maxn)-getleft(a-1); int right=getright(maxn)-getright(b); printf("%d\n",max(0,left-right)); addleft(a,1); addright(b,1); } else { int id=arr[i].a-1; int a=lower_bound(s,s+ind,add[id].a)-s+1;//lisan int b=lower_bound(s,s+ind,add[id].b)-s+1; // printf("delete: id=%d %d %d\n",id,a,b); addleft(a,-1); addright(b,-1); } } } return 0; } /* 6 0 1 0 0 1 2 0 0 1 3 0 0 ans: 0 1 1 1 */
HDU5373
求n经过t次迭代变换后是否能整出11,n->n+n的每位数之和 为一次变换
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define ll long long int s,n,t; int sum,p; void run(int n) { p=1; while(n) { p*=10; sum+=n%10; n/=10; } } int main() { int ca=1; while(~scanf("%d%d",&n,&t)) { if(n==-1&&t==-1) break; sum=0; int s=n; int ans=0; t++; while(t--) { run(s); ans=(ans*p+s)%11; s=sum; } if(ans%11==0)printf("Case #%d: Yes\n",ca++); else printf("Case #%d: No\n",ca++); } return 0; }
HDU5375
gray码是由相邻二进制码两两抑或得到的,第一个gray码就是第一个二进制码
当前的状态只和前一状态有关,dp分类讨论即可
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<queue> using namespace std; int dp[200020][2]; char s[200020]; int a[200020]; int main() { int T; scanf("%d",&T); s[0]='0'; for(int ca=1;ca<=T;ca++) { memset(dp,0,sizeof(dp)); scanf("%s",s+1); int n=strlen(s+1); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) { if(s[i]=='0') { if(s[i-1]=='0')dp[i][0]=dp[i-1][0]; else if(s[i-1]=='1')dp[i][0]=dp[i-1][1]+a[i]; else dp[i][0]=max(dp[i-1][0],dp[i-1][1]+a[i]); } else if(s[i]=='1') { if(s[i-1]=='0')dp[i][1]=dp[i-1][0]+a[i]; else if(s[i-1]=='1')dp[i][1]=dp[i-1][1]; else dp[i][1]=max(dp[i-1][0]+a[i],dp[i-1][1]); } else{ if(s[i-1]=='0')dp[i][0]=dp[i-1][0]; else if(s[i-1]=='1')dp[i][0]=dp[i-1][1]+a[i]; else dp[i][0]=max(dp[i-1][0],dp[i-1][1]+a[i]); if(s[i-1]=='0')dp[i][1]=dp[i-1][0]+a[i]; else if(s[i-1]=='1')dp[i][1]=dp[i-1][1]; else dp[i][1]=max(dp[i-1][0]+a[i],dp[i-1][1]); } } printf("Case #%d: %d\n",ca,max(dp[n][0],dp[n][1])); } return 0; }
HDU5379
给定一棵n个节点的数,和一组编号1.2.3...n的麻将牌,要求:
1.每个节点只能放一个麻将牌
2.父亲的所有直接儿子上面的麻将牌要连续
3.所有子树上面的麻将牌要连续
求放置的方法数。
题目就是求一个连续序列能分成k段的方法数目,bfs求解。对于每棵子树而言,
1.只要有儿子节点,方法数*2 (由于是一棵树,邻接表中v[i].size()>1就说明有儿子。
2.有孙子的儿子节点最多只能有两个。
3.如果有孙子的儿子节点>=1个,方法数*2
4.没有孙子的儿子节点数为k个,方法数*k!
5.数据范围longlong
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<queue> using namespace std; #define ll long long #define maxn 100010 #define mod 1000000007 vector<int>s[maxn]; int n; int v[maxn]; ll ans; void bfs() { queue<int>q; memset(v,0,sizeof(v)); while(!q.empty())q.pop(); q.push(0); ans=1; v[0]=1; while(!q.empty()) { int fa=q.front(); q.pop(); int num=0; int sig=0; for(int i=0;i<s[fa].size();i++) { int su=s[fa][i]; if(!v[su]) { v[su]=1; if(s[su].size()>1)num++; else sig++; q.push(su); } } if(num>2){ ans=0; return; } if(num!=0)ans=(ans*2)%mod; for(int i=1;i<=sig;i++) { ans=(ans*i)%mod; } } } int main() { int T; scanf("%d",&T); for(int ca=1;ca<=T;ca++) { scanf("%d",&n); for(int i=0;i<=n;i++)s[i].clear(); int u,v; s[0].push_back(1); s[1].push_back(0); for(int i=0;i<n-1;i++) { scanf("%d%d",&u,&v); s[u].push_back(v); s[v].push_back(u); } bfs(); printf("Case #%d: %lld\n",ca,ans); } return 0; }