WHUST 2015 Summer Contest #0.1

A - Queries on the Tree

题意: 根节点为1的一棵树,有两种类型的操作,第一种是1 L Y, 把距离根节点L的结点值增加Y, 2 X, 查询以X为跟的子树的和。

思路: 1. 使用DFS搞成区间序列的形式 2. 对于操作1,把这个结点深度的值存储下来,依次增加(!)  3. 对于操作2,明显是一个区间和查询。

          根据上述思路, 这不就是一个普通的区间和的东西吗?

          但是,有一个问题, 在思路2那里,如果真的依次增加, 那么一定会超时的。 这个时候可以进行分块, 把深度为L的结点进行分块操作。 快内的依次暴力解决, 然后快外的再依次解决。

          

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int M = 1000;
const int N = 100007;
vector<int> pos[N],e[N],c;
LL b[N],s[N];
int l[N],r[N],lst[N],cnt=0,n;
void add(int x,LL v) {for (;x<=n;x+=x&(-x)) b[x]+=v;}
LL sum(int x) {LL ans=0;for (;x;x-=x&(-x)) ans+=b[x];return ans;}
void dfs(int x,int d)
{
    lst[++cnt]=x;
    l[x]=cnt;
    pos[d].push_back(cnt);
    for (auto &p:e[x])
        dfs(p,d+1);
    r[x]=cnt;
}
int main()
{
    int m,x,y;
    scanf("%d%d",&n,&m);
    for (int i=0;i<n-1;++i)
    {
        scanf("%d%d",&x,&y);
        e[x].push_back(y);
    }
    dfs(1,0);
    for (int i=0;i<n;++i)
        if (pos[i].size()>M)
            c.push_back(i);
    for (int i=0;i<m;++i)
    {
        scanf("%d",&x);
        if (x==1)
        {
            scanf("%d%d",&x,&y);
            if (pos[x].size()<=M)
                for (auto &p:pos[x])
                    add(p,y);
            else
                s[x]+=y;
        }
        else
        {
            scanf("%d",&x);
            LL ans=sum(r[x])-sum(l[x]-1);
            for (auto &p:c)
                ans+=(upper_bound(pos[p].begin(),pos[p].end(),r[x])
                    -lower_bound(pos[p].begin(),pos[p].end(),l[x]))*s[p];
            cout << ans << endl;
        }
    }
    return 0;
}

  B - Count Palindromes

  水题: 问从t1到t2时刻,中间有几个时刻构成的字符串是回文的。

 

#include<bits/stdc++.h>

using namespace std;

int f[100000];

void init()
{
    for (int h=0;h<=24;h++)
        for (int m=0;m<60;m++)
            for (int s=0;s<60;s++)
    {
        int t=h*3600+m*60+s+1;
        if (h/10==s%10&&h%10==s/10&&m/10==m%10) f[t]=f[t-1]+1; else f[t]=f[t-1];
    }
}

int main()
{
    int T,h1,m1,s1,h2,m2,s2;
    init();
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d:%d:%d",&h1,&m1,&s1);
        scanf("%d:%d:%d",&h2,&m2,&s2);
        int t1=h1*3600+m1*60+s1+1;
        int t2=h2*3600+m2*60+s2+1;
        printf("%d\n",f[t2]-f[t1-1]);
    }
    return 0;
}

  C - Find P'th Number

水题:去掉奇数问第p小的数或者去掉偶数问第p小的数字

   

#include<bits/stdc++.h>

using namespace std;

int n,p,ans;
char s[10];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%s%d",&n,s,&p);
        if (s[0]=='o') ans=2*p; else ans=2*p-1;
        printf("%d\n",ans);
    }
    return 0;
}

  D - Desolation of Smaug

      E - Count Distinct Sets

      F - Count Ways

题意:问从(1,1) 到(n,m)有多少种走法,只能向下或者向右, 并且有k个点不能走。

思路:第一个重要的点, 得需要知道从(1,1)到(n,m), 假设中间没有障碍点,一共有C(n+m-2,n-1)种走法(最重要)。

        

    假设x1,y1为障碍点, 那么到达x2,y2的走法应该是C(x2+y2-2,x2-1)-C(x1+y1-2,x1-1)*C(x2-x1+y2-y2,x2-x1) 也就是看成中间那个从x1,y1到x2,y2的小矩形。

    计算C需要用到乘法逆元。

    

#include<bits/stdc++.h>
#define N 200010
#define LL long long
const LL MOD=1e9+7;

using namespace std;

struct node
{
    int x,y;
};

node a[N];
LL p[N],q[N];
LL f[N];
LL x,y,gcd;

void ex_gcd(LL a, LL b)
{
    if (!b) {x=1; y=0; gcd=a;}
    else {ex_gcd(b,a%b); LL temp=x; x=y; y=temp-a/b*y;}
}

void init()
{
    q[0]=1;
    p[0]=1;
    for (int i=1;i<N;i++)
    {
        p[i]=p[i-1]*i%MOD;
        ex_gcd(i,MOD);
        while(x<0) x+=MOD;
        q[i]=q[i-1]*x%MOD;
    }
}

bool cmp(node a, node b)
{
    return (a.x<b.x)||(a.x==b.x&&a.y<b.y);
}

LL C(int x, int y)
{
    return p[x]*q[y]%MOD*q[x-y]%MOD;
}

int main()
{
    int T,n,m,k;
    init();
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&k);
        for (int i=0;i<k;i++) scanf("%d%d",&a[i].x,&a[i].y);
        a[k].x=n; a[k++].y=m;
        sort(a,a+k,cmp);
        for (int i=0;i<k;i++) f[i]=C(a[i].x+a[i].y-2,a[i].x-1);
        for (int i=0;i<k;i++)
            for (int j=0;j<i;j++)
            if (a[j].y<=a[i].y)
        {
            f[i]=(f[i]+MOD-f[j]*C(a[i].x-a[j].x+a[i].y-a[j].y,a[i].x-a[j].x)%MOD)%MOD;
        }
        printf("%I64d\n",f[k-1]);
    }
    return 0;
}

  G - Count Permutations

  题意:问从1到N的排列中, 相邻数字差的绝对值不大于K的有多少种排列。

  使用位运算的第i位来表示i是否使用过。然后DP

#include<bits/stdc++.h>
#define N 40000
#define LL long long

using namespace std;

LL f[N][20];

int main()
{
    int T,n,k;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        memset(f,0,sizeof(f));

        for (int i=1;i<=n;i++) f[1<<(i-1)][i]=1;
        for (int s=1;s<(1<<n);s++)
            for (int i=1;i<=n;i++)
            if ((s>>(i-1))&1)
            {
                for (int j=max(1,i-k);j<=min(n,i+k);j++)
                if (i!=j&&((s>>(j-1))&1)) f[s][i]+=f[s^(1<<(i-1))][j];
            }
        LL ans=0;
        for (int i=1;i<=n;i++) ans+=f[(1<<n)-1][i];
        printf("%I64d\n",ans);
    }
    return 0;
}

  H - Count Subarrays

 题意:问在序列1……N中有多少个连续子序列中的逆序对数不少于K。

 从左端点开始,逆序对数是单调递增的。于是可以维护一个右端点。

注意 使用upper_bound 一定需要注意范围!

 

#include<bits/stdc++.h>
#define N 100010
#define LL long long

using namespace std;

int a[N],b[N];
int n,m;
LL k;
LL d[N];

int lowbit(int x)
{
    return x&(-x);
}

void update(int x, int num)
{
    while(x<=m)
    {
        d[x]+=num;
        x+=lowbit(x);
    }
}

LL sum(int x)
{
    LL s=0;
    while(x>0)
    {
        s+=d[x];
        x-=lowbit(x);
    }
    return s;
}

int main()
{
    LL ans,t;
    while(scanf("%d%I64d",&n,&k)!=EOF)
    {
        ans=0;
        for (int i=1;i<=n;i++) scanf("%d",&a[i]);
        for (int i=0;i<n;i++) b[i]=a[i+1];
        sort(b,b+n);
        m=unique(b,b+n)-b;
        for (int i=1;i<=m;i++) d[i]=0;
        for (int i=1;i<=n;i++) a[i]=lower_bound(b,b+m,a[i])-b+1;


        int j=0;
        t=0;
        for (int i=1;i<=n;i++)
        {
            if (j<i) { update(a[++j],1);t=0;}
            while(t<k&&j<n)
            {
                update(a[++j],1);
                t=t+sum(m)-sum(a[j]);
            }
            if (t>=k&&j<=n) ans=ans+n-j+1;
            t=t-sum(a[i]-1);
            update(a[i],-1);
        }
        printf("%I64d\n",ans);
        /*
        LL L=1,num=0;
        for (int i=1;i<=n;i++)
        {
            num+=sum(m)-sum(a[i]);
            update(a[i],1);
            if (num>=k) ans=ans+L;
            while(num>=k && L<i)
            {
                LL tp=sum(a[L]-1);
                if (num-tp>=k)
                {
                    num-=tp;
                    update(a[L],-1);
                    L++;
                    ans++;
                }
                else break;
            }
        }
         printf("%I64d\n",ans);*/
    }
    return 0;
}

  I - Laughing Out Loud

水题

#include<bits/stdc++.h>
#define N 100010
#define LL long long

char s[N];
LL L[N],O[N];

using namespace std;

int main()
{
    int T,len;
    LL ans;
    scanf("%d",&T);
    while(T--)
    {
        ans=0;
        scanf("%s",s);
        len=strlen(s);
        O[0]=L[0]=0;
        for (int i=0;i<len;i++)
        {
            if (s[i]=='L') L[i+1]=L[i]+1; else L[i+1]=L[i];
            if (s[i]=='O') O[i+1]=O[i]+L[i]; else O[i+1]=O[i];
        }
        for (int i=0;i<len;i++)
            if (s[i]=='L')
        {
            ans=ans+O[i+1];
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

  J - Three Sorted Arrays

题意 1 ≤ i ≤ j ≤ k, such that: A[i] ≤ B[j] ≤ C[k].  存在多少对这样的情况

二分和前缀和的应用

#include<bits/stdc++.h>
#define N 100010
#define LL long long

using namespace std;
LL a[N],b[N],c[N];
LL f[N];

int main()
{
    int T,p,q,r;
    LL ans;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&p);
        for (int i=1;i<=p;i++) scanf("%I64d",&a[i]);
        scanf("%d",&q);
        for (int i=1;i<=q;i++) scanf("%I64d",&b[i]);
        scanf("%d",&r);
        for (int i=1;i<=r;i++) scanf("%I64d",&c[i]);

        f[0]=0;
        ans=0;
        for (int i=1;i<=q;i++)
        {
            int j=lower_bound(c+i,c+r+1,b[i])-c;
            if (j<=r) f[i]=f[i-1]+(LL)(r-j+1); else f[i]=f[i-1];
        }

        for (int i=1;i<=p;i++)
        {
            int j=lower_bound(b+i,b+q+1,a[i])-b;
            if (j<=q) ans=ans+f[q]-f[j-1];
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

  K - Police Catching Thief

posted on 2015-08-12 09:14  wzb_hust  阅读(136)  评论(0编辑  收藏  举报

导航