BestCoder Round #77

链接:http://bestcoder.hdu.edu.cn/

分析:1001,子集异或和的异或和,除了n==1的情况外所有元素都会在偶数个子集中出现,所以特判一下即可。O(n)

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=200100;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000009;
const ll INF=10000000010;
typedef double db;
typedef unsigned long long ull;
int main()
{
    int i,n,x,t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        for (i=1;i<=n;i++) scanf("%d", &x);
        if (n>1) printf("0\n");
        else printf("%d\n", x);
    }
    return 0;
}

分析:1002,回文串的个数,先判断一下奇数个元素的个数来确定是否能组成回文串,再用组合数求解即可。O(n)

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=50010;
const int MOD1=1000007;
const int MOD2=100000009;
const int MAX=1000000000;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
const ll INF=10000000010;
const double pi=acos(-1.0);
typedef double db;
typedef unsigned long long ull;
int g[30];
ll f[1010];
char s[1010];
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y) {
    if (!b) { d=a;x=1;y=0; }
    else { ex_gcd(b,a%b,d,y,x);y-=x*(a/b); }
}
ll inv(ll a,ll n) {
    ll d,x,y;
    ex_gcd(a,n,d,x,y);
    return d==1 ? (x+n)%n:-1;
}
ll get(ll x) {
    ll ret=1;
    for (int i=1;i<=x;i++) ret=ret*i%MOD;
    return inv((ret+MOD)%MOD,MOD);
}
int main()
{
    int i,t,odd,len;
    ll ans;
    scanf("%d", &t);
    f[1]=1LL;
    for (i=2;i<=1005;i++) f[i]=get(i);
    while (t--) {
        scanf("%s", s);
        len=strlen(s);odd=0;
        memset(g,0,sizeof(g));
        for (i=0;i<len;i++) g[s[i]-'a'+1]++;
        for (i=1;i<27;i++)
        if (g[i]&1) odd++;
        if (!(len&1)&&odd) { printf("0\n");continue ; }
        if ((len&1)&&odd!=1) { printf("0\n");continue ; }
        ans=1LL;
        for (i=1;i<=len/2;i++) ans=ans*i%MOD;
        for (i=1;i<27;i++)
        if (g[i]/2) ans=ans*f[g[i]/2]%MOD;
        printf("%d\n", (ans+MOD)%MOD);
    }
    return 0;
}

分析:1003,先将所有的山添加进地图,对所有平原节点做4联通并查集,然后从最后一座山开始删除,什么时候节点0和节点n*m+1联通了就输出答案即可。O(n*mlog(n*m))

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=510;
const int MAX=151;
const int mod=100000000;
const int MOD1=100000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000009;
const ll INF=10000000010;
typedef double db;
typedef unsigned long long ull;
char s[N];
int ma[N][N],f[N*N],x[N*N],y[N*N];
int find_f(int x) {
    return f[x]==x ? x:f[x]=find_f(f[x]);
}
void unio(int a,int b) {
    int fa=find_f(a),fb=find_f(b);
    if (fa!=fb) f[fa]=fb;
}
int main()
{
    int i,j,k,q,t,n,m,sum;
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d", &n, &m);
        sum=n*m;memset(ma,0,sizeof(ma));
        for (i=1;i<=n;i++) {
            scanf("%s", s);
            for (j=0;j<m;j++) ma[i][j+1]=s[j]-'0';
        }
        for (i=0;i<=sum+1;i++) f[i]=i;
        scanf("%d", &q);
        for (i=1;i<=q;i++) {
            scanf("%d%d", &x[i], &y[i]);
            x[i]++;y[i]++;ma[x[i]][y[i]]=1;
        }
        for (i=1;i<=m;i++) {
            if (!ma[1][i]) unio(0,i);
            if (!ma[n][i]) unio((n-1)*m+i,sum+1);
        }
        for (i=1;i<=n;i++)
            for (j=1;j<=m;j++)
            if (!ma[i][j]) {
                k=(i-1)*m+j;
                if (i>1&&!ma[i-1][j]) unio(k,k-m);
                if (i<n&&!ma[i+1][j]) unio(k,k+m);
                if (j>1&&!ma[i][j-1]) unio(k,k-1);
                if (j<m&&!ma[i][j+1]) unio(k,k+1);
            }
        if (find_f(0)==find_f(sum+1)) { printf("-1\n");continue ; }
        for (i=q;i;i--) {
            k=(x[i]-1)*m+y[i];ma[x[i]][y[i]]=0;
            if (x[i]>1&&!ma[x[i]-1][y[i]]) unio(k,k-m);
            if (x[i]<n&&!ma[x[i]+1][y[i]]) unio(k,k+m);
            if (y[i]>1&&!ma[x[i]][y[i]-1]) unio(k,k-1);
            if (y[i]<m&&!ma[x[i]][y[i]+1]) unio(k,k+1);
            if (k<=m) unio(0,k);
            if (k>(n-1)*m) unio(k,sum+1);
            if (find_f(0)==find_f(sum+1)) break ;
        }
        printf("%d\n", i);
    }
    return 0;
}


分析:1004,裸的DP,直接设dp[i]表示到第i个点时的最大价值。O(n^2)

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=2010;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000009;
const ll INF=10000000010;
typedef double db;
typedef unsigned long long ull;
int q[N];
db dp[N];
int main()
{
    int i,j,g,n,m,t,x;
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d", &n, &m);
        memset(q,0,sizeof(q));
        for (i=1;i<=m;i++) {
            scanf("%d", &x);q[x+1]=1;
        }
        memset(dp,0,sizeof(dp));
        for (i=1;i<=n;i++) {
            g=0;
            for (j=i;j>0;j--) {
                if (q[j]) g++;
                if (g>1) break ;
                if (g==1) dp[i]=max(dp[i],dp[j-1]+log2(i-j+1));
            }
        }
        printf("%d\n", (int)(1000000*dp[n]));
    }
    return 0;
}


分析:1005,排序处理完相同3元组之后就变成了经典的求区间颜色数啦。方法1:离线按询问的r排序,用树状数组维护每种3元组出现的最后位置,O(nlogn+mlogn)。方法2:维护每一个3元组出现的前一次的位置pre[i],询问区间[l,r]时只有统计pre[l]~pre[r]中有多少是小于l的即可,用可持久化线段树维护下就行了,O(nlogn+mlogn)。

代码:(树状数组)

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=200100;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000009;
const ll INF=10000000010;
typedef double db;
typedef unsigned long long ull;
struct node {
    int l,r,id;
}q[N];
struct xxx {
    int x,y,z,w;
}d[N];
int n,a[N],f[N],g[N],ans[N],pre[N];
int cmd(xxx a,xxx b) {
    if (a.x!=b.x) return a.x<b.x;
    if (a.y!=b.y) return a.y<b.y;
    if (a.z!=b.z) return a.z<b.z;
    return a.w<b.w;
}
int cmd1(node a,node b) {
    return a.r<b.r;
}
void add(int x,int y) {
    if (x<=0) return ;
    for (;x<=n-2;x+=x&(-x)) g[x]+=y;
}
int getsum(int x) {
    int ret=0;
    if (x<=0) return 0;
    for (;x;x-=x&(-x)) ret+=g[x];
    return ret;
}
int main()
{
    int i,k,t,m,R;
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        for (i=1;i<=n;i++) scanf("%d", &a[i]);
        for (i=1;i<=n-2;i++) {
            d[i].x=a[i];d[i].y=a[i+1];d[i].z=a[i+2];d[i].w=i;
        }
        sort(d+1,d+n-1,cmd);
        k=0;d[0].x=d[0].y=d[0].z=-1;
        for (i=1;i<=n-2;i++)
        if (d[i].x<=d[i].y&&d[i].y<=d[i].z) {
            if (d[i].x==d[i-1].x&&d[i].y==d[i-1].y&&d[i].z==d[i-1].z) f[d[i].w]=k;
            else f[d[i].w]=++k;
        } else f[d[i].w]=0;
        memset(g,0,sizeof(g));
        for (i=1;i<=n-2;i++) {
            pre[i]=g[f[i]];g[f[i]]=i;
        }
        scanf("%d", &m);
        for (i=1;i<=m;i++) {
            scanf("%d%d", &q[i].l, &q[i].r);q[i].id=i;
        }
        memset(g,0,sizeof(g));
        sort(q+1,q+m+1,cmd1);R=0;
        for (i=1;i<=m;i++) {
            while (R<q[i].r) {
                R++;
                if (R>2&&f[R-2]!=0) { add(pre[R-2],-1);add(R-2,1); }
            }
            if (q[i].r-q[i].l<2) ans[q[i].id]=0;
            else ans[q[i].id]=getsum(q[i].r-2)-getsum(q[i].l-1);
        }
        for (i=1;i<=m;i++) printf("%d\n", ans[i]);
    }
    return 0;
}

代码:(可持久化线段树)

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=200100;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000009;
const ll INF=10000000010;
typedef double db;
typedef unsigned long long ull;
struct xxx {
    int x,y,z,w;
}d[N];
int a[N],f[N],pre[N];
int cmd(xxx a,xxx b) {
    if (a.x!=b.x) return a.x<b.x;
    if (a.y!=b.y) return a.y<b.y;
    if (a.z!=b.z) return a.z<b.z;
    return a.w<b.w;
}
int siz,root[20*N],ls[20*N],rs[20*N],sum[20*N];
void updata(int l,int r,int x,int &y,int z) {
    y=++siz;
    sum[y]=sum[x]+1;
    if (l==r) return ;
    ls[y]=ls[x];rs[y]=rs[x];
    int mid=(l+r)>>1;
    if (z<=mid) updata(l,mid,ls[x],ls[y],z);
    else updata(mid+1,r,rs[x],rs[y],z);
}
int getsum(int l,int r,int x,int y,int z) {
    if (r==z) return sum[y]-sum[x];
    int mid=(l+r)>>1;
    if (z<=mid) return getsum(l,mid,ls[x],ls[y],z);
    else return sum[ls[y]]-sum[ls[x]]+getsum(mid+1,r,rs[x],rs[y],z);
}
int main()
{
    int i,k,t,n,m,l,r;
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        for (i=1;i<=n;i++) scanf("%d", &a[i]);
        for (i=1;i<=n-2;i++) {
            d[i].x=a[i];d[i].y=a[i+1];d[i].z=a[i+2];d[i].w=i;
        }
        sort(d+1,d+n-1,cmd);
        k=0;d[0].x=d[0].y=d[0].z=-1;
        for (i=1;i<=n-2;i++)
        if (d[i].x<=d[i].y&&d[i].y<=d[i].z) {
            if (d[i].x==d[i-1].x&&d[i].y==d[i-1].y&&d[i].z==d[i-1].z) f[d[i].w]=k;
            else f[d[i].w]=++k;
        } else f[d[i].w]=0;
        memset(a,0,sizeof(a));
        for (i=1;i<=n-2;i++) {
            pre[i]=a[f[i]]+1;a[f[i]]=i;
            if (!f[i]) pre[i]=n;
        }
        siz=sum[0]=root[0]=0;
        for (i=1;i<=n-2;i++) updata(1,n,root[i-1],root[i],pre[i]);
        scanf("%d", &m);
        while (m--) {
            scanf("%d%d", &l, &r);
            if (r-l<2) printf("0\n");
            else printf("%d\n", getsum(1,n,root[l-1],root[r-2],l));
        }
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值