2012天津现场赛

这场去了天津现场,做的明显不如网赛来的顺利,感觉自己准备的很不充分啊,努力刷题吧~~

Str2int

用后缀自动机来搞。将给定的串用10这个字符连接起来,建一个SAM,然后按照节点代表的串长度bfs一下,来一个dp就可以求出答案了。

如果用SA来解,必须预处理后在O(1)的时间得到[l,r]区间的所有前缀和,蛋疼。

还是最简状态自动机简单些。明显状态和阶段都好了,dp一下就出来了,具体看代码。

#include<cstdio>
#include<cstdlib>
#include<queue>
#include<vector>
#include<string.h>
using namespace std;
const int MAX=410003;
const int NUM=12;
const char BASE='0';
const int mod=2012;
#define End
struct node{
    node* ch[NUM],*fa;
    int len,hash,num;
#ifdef End
    int end;
#endif
    node(){}
    node(node* father,int lenth)
    {
        fa=father;
        len=lenth;
        hash=0;num=0;
#ifdef End
        end=0;
#endif
        memset(ch,0,sizeof ch);
    }
}tree[MAX],*Root;
int cnt;
bool vis[MAX];
void SAM(char* a,int n){
    cnt=0;
    memset(tree,0,sizeof(tree));
    Root=tree+(cnt++);
    *Root=node(0,0);
    node *p=Root,*np,*op,*cp;
    int i,idx;
    for(i=0;i<n;++i)
    {
        idx=a[i]-BASE;
        np=tree+(cnt++);
        *np=node(0,i+1);
        np->num=0;
#ifdef End
        np->end=i;
#endif
        while(p && !p->ch[idx])
            p->ch[idx]=np,p=p->fa;
        if(p && p->ch[idx])
        {
            op=p->ch[idx];
            if(p->len+1==op->len)
                np->fa=op;
            else
            {
                cp=tree+(cnt++);
                *cp=*op;
                cp->num=0;
#ifdef End
                cp->end=i;
#endif
                cp->len=p->len+1;
                op->fa=cp;np->fa=cp;
                while(p && p->ch[idx]==op)
                    p->ch[idx]=cp,p=p->fa;
            }
        }
        else np->fa=Root;
        p=np;
    }
}int n,m;
char s[MAX];
vector<node*> hh[MAX];
int bfs()
{
    memset(vis,0,sizeof(vis));
    int sum=0,idx,i,j;
    Root->num=1;
    for(i=0;i<=n;++i)
      while (!hh[i].empty()) hh[i].clear();
    for(i=0;i<cnt;++i)
        hh[tree[i].len].push_back(tree+i);
    for(i=0;i<=n;i++)
        for(j=hh[i].size()-1;j>=0;--j)
        {
            if (!hh[i][j]->num) continue;
            for (idx=0; idx<10; idx++)
            {
                if (hh[i][j]==Root && idx==0) continue;
                if (hh[i][j]->ch[idx]){
                    hh[i][j]->ch[idx]->hash+=
                      hh[i][j]->hash*10+idx*hh[i][j]->num;
                    hh[i][j]->ch[idx]->hash%=mod;
                    hh[i][j]->ch[idx]->num+=hh[i][j]->num;
                    sum+=hh[i][j]->hash*10+idx*hh[i][j]->num;
                    sum%=mod;
                }
            }
        }
    return sum;
}
int main()
{
    int m,sum,i,len;
    char *sp;
    while ( ~scanf("%d",&m) )
    {
        memset(s,0,sizeof(s));
        n=sum=0;
        sp=s;
        for (i=0; i<m; i++)
        {
            scanf("%s",sp);
            len=strlen(sp);
            sp+=len;
            *(sp++)='0'+10;
        }
        *sp=0;
        n=strlen(s);
        SAM(s,n);
        sum=bfs();
        printf("%d\n",sum);
    }
    return 0;
}

 

 

 

charge-station

简单贪心题。城市i的费用比所有小于i的城市费用和都高(这个在二进制下很容易看出来)。

所以先假设全部城市都建加油站,check()一下,不满足题意就puts("-1");

然后从高到低逐个删去城市,如果check()满足,那么果断删掉,如果出现不满足的情况,就不能删掉。重复此过程一直到第二个城市。

最后输出结果,为了方便题目叫我们直接输出二进制。

(-这么简单的题居然没做,低头....(-

#include<cstdio>
#include<cstring>
#include<cmath>
const int N = 130;
struct node{
    int x,y;//maybe in double;
}a[N];
int n,d;
int g[N][N];
int distance(node &a, node &b){
    int ret,dx,dy;
    dx=a.x-b.x, dy=a.y-b.y;
    ret=sqrt( dx*dx+dy*dy );
    if (ret*ret == dx*dx + dy*dy) return ret;
    else return ret+1;
}
bool vis[N];
int q[N],ans[N];
bool check(){
    int i,head,tail,t;
    memset(vis,0,sizeof(vis));
    vis[0]=1, q[0]=0, head=1, tail=0;
    while (tail<head){
        t=q[tail++];
        for (i=0; i<n; i++)
          if (!vis[i]){
            if (ans[i]){
                if (g[t][i]<=d) {
                    q[head++]=i, vis[i]=1;
                    //printf("@%d %d\n",t,i);
                }
            }else{
                if (g[t][i]+g[i][t]<=d) {
                    vis[i]=1;
                    //printf("@%d %d\n",t,i);
                }
            }
          }
    }
    for (i=0; i<n; i++) if (vis[i]==0) return false;
    return true;
}
void solve(){
    int i;
    for (i=0; i<n; i++) ans[i]=1;
    if (!check()) {
        puts("-1");
        return ;
    }
    for (i=n-1; i>0; i--){
        ans[i]=0;//assert
        //printf("@erase:%d\n",i);
        if (!check()) {
            ans[i]=1;
        }
    }
    i=n-1;
    while (ans[i]==0) i--;

    for (; i>=0; i--) if (ans[i]) printf("1");else printf("0");
    puts("");
}
int main(){
    int i,j;
    while ( ~scanf("%d%d",&n,&d) ){
        for (i=0; i<n; i++)
          scanf("%d %d", &a[i].x, &a[i].y);
        for (i=0; i<n; i++)
          for (j=0; j<n; j++)
            g[i][j]=distance(a[i],a[j]);
        solve();
    }
    return 0;
}


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值