2015 Multi-University Training Contest 7

Start Time : 2015-08-11 12:00:00    End Time : 2015-08-11 17:00:00
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;
}
View Code

 

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
*/
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

posted on 2015-08-12 21:54  kylehz  阅读(269)  评论(0编辑  收藏  举报