2016"百度之星" - 资格赛(Astar Round1)

题目比较基础。

A题:

算字符串连续子串的hash,线段树维护hash,这里并不是标准的hash,所以没难度。

当然用前缀和+逆元好像也可以,不过我没想清楚如果被除数为0怎么处理逆元。

#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

const ll MOD=9973;
ll H[maxn<<2];
int n;
char s[maxn];int len;
int L,R;

void push_up(int rt)
{
    H[rt]=(H[rt<<1]*H[rt<<1|1])%MOD;
}

void build(int l,int r,int rt)
{
    if(l==r){
        H[rt]=(s[l]+MOD-28)%MOD;
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    push_up(rt);
}

ll query(int L,int R,int l,int r,int rt)
{
    if(L>R) return 0;
    //cout<<"L="<<L<<" R="<<R<<" l="<<l<<" r="<<r<<" rt="<<rt<<" Hrt="<<H[rt]<<endl;
    if(L<=l&&r<=R) return H[rt];
    int m=(l+r)>>1;
    ll res=1;
    if(L<=m) res=(res*query(L,R,lson))%MOD;
    if(R>m) res=(res*query(L,R,rson))%MOD;
    return res;
}

int main()
{
    //freopen("in.txt","r",stdin);
    while(~scanf("%d",&n)){
        scanf("%s",s+1);
        len=strlen(s+1);
        build(1,len,1);
        while(n--){
            scanf("%d%d",&L,&R);
            printf("%I64d\n",query(L,R,1,len,1));
        }
    }
    return 0;
}
View Code

B题:

设前i个的方案数为f[i],那么第i个要么和前一个合并,方案数为f[i-2],要么不合并,方案数为f[i-1],所以f[i]=f[i-1]+f[i-2]。

由于斐波那契数列是指数级的,所以第200个肯定爆了longlong,需要模拟大数加法,或者直接用java。

#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;

typedef unsigned long long ll;
const int maxn=1000100;
const int INF=1e9+10;

int n;
string s[210];

string add(string a,string b)
{
    string c="";
    int la=a.size(),lb=b.size();
    int tag=0;
    if(la>lb) swap(la,lb),swap(a,b);
    //cout<<"a="<<a<<" b="<<b<<endl;
    REP(i,0,la-1){
        int t=a[i]-'0'+b[i]-'0'+tag;
        c+=(char)(t%10+'0');
        tag=t/10;
    }
    REP(i,la,lb-1){
        int t=b[i]-'0'+tag;
        c+=(char)(t%10+'0');
        tag=t/10;
    }
    if(tag) c+=(char)(tag+'0');
    //cout<<"c="<<c<<endl;
    return c;
}

void Init()
{
    s[0]=s[1]="1";
    REP(i,2,201) s[i]=add(s[i-1],s[i-2]);
}

int main()
{
    //freopen("in.txt","r",stdin);
    Init();
    while(~scanf("%d",&n)){
        if(n<=0) puts("");
        else{
            for(int i=s[n].size()-1;i>=0;i--) printf("%c",s[n][i]);puts("");
        }
    }
    return 0;
}
View Code

C题:

很基础的trie,直接维护个数sz,模拟插入删除就可以了,每次修改经过路径的值,删除结点的时候不用内存池回收,空间是够用的。

#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;

typedef unsigned long long ll;
const int maxn=3000100;
const int INF=1e9+10;

struct Trie
{
    int ch[maxn][26];
    int rt,tot;
    int sz[maxn];
    int newnode()
    {
        ++tot;
        MS0(ch[tot]);
        sz[tot]=0;
        return tot;
    }
    void init()
    {
        tot=0;
        rt=newnode();
    }
    void insert(char *s)
    {
        int len=strlen(s);
        int u=rt;
        REP(i,0,len-1){
            int c=s[i]-'a';
            if(!ch[u][c]) ch[u][c]=newnode();
            sz[ch[u][c]]++;
            u=ch[u][c];
        }
    }
    void del(char *s)
    {
        int len=strlen(s);
        int u=rt;
        REP(i,0,len-1){
            int c=s[i]-'a';
            if(!ch[u][c]) return;
            u=ch[u][c];
        }
        int t=sz[u];
        u=rt;
        REP(i,0,len-1){
            int c=s[i]-'a';
            u=ch[u][c];
            sz[u]-=t;
        }
        REP(c,0,25) ch[u][c]=0;
    }
    bool find(char *s)
    {
        int len=strlen(s);
        int u=rt;
        REP(i,0,len-1){
            int c=s[i]-'a';
            if(!ch[u][c]) return 0;
            u=ch[u][c];
        }
        return sz[u]!=0;
    }
};Trie tr;
int n;
char op[maxn],s[maxn];

int main()
{
    while(cin>>n){
        tr.init();
        REP(i,1,n){
            scanf("%s%s",op,s);
            if(op[0]=='i') tr.insert(s);
            else if(op[0]=='d') tr.del(s);
            else puts(tr.find(s)?"Yes":"No");
        }
    }
    return 0;
}
View Code

D题:

map记录一下出现次数就可以了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<string>
#include<map>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

int n;
string s;
map<string,int> cnt;

int main()
{
    while(cin>>n){
        cnt.clear();
        REP(i,1,n){
            cin>>s;
            sort(s.begin(),s.end());
            printf("%d\n",cnt[s]);
            cnt[s]++;
        }
    }
    return 0;
}
View Code

E题:

由于变量只有30个,所以将每个条件每个变量的解集初始化为[-INF,INF],然后读入条件,和前面的暴力判断一下交集就可以了。

主要是读入的过程,算是不太麻烦的小模拟。

#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<map>
#include<string>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;

typedef unsigned long long ll;
const int maxn=3000100;
const int INF=1e9+10;

int cn;
struct Node
{
    int L[40],R[40];
    bool kong;
};Node a[maxn];
map<string,int> id;
int n;
char s[maxn];

int main()
{
    freopen("in.txt","r",stdin);
    while(cin>>n){
        id.clear();
        REP(i,1,n) REP(j,1,30) a[i].L[j]=-INF,a[i].R[j]=INF,a[i].kong=0;
        cn=0;
        gets(s);
        //cout<<"s="<<s<<endl;
        REP(i,1,n){
            gets(s);
            int len=strlen(s);
            //cout<<"s="<<s<<endl;
            for(int j=0;j<len;){
                while(j<len&&s[j]==' ') j++;
                string name="";
                while(j<len&&s[j]!=' ') name+=s[j++];
                while(j<len&&s[j]==' ') j++;
                string p="";
                while(j<len&&s[j]!=' ') p+=s[j++];
                while(j<len&&s[j]==' ') j++;
                int num=0;
                int ttt=1;
                if(s[j]=='-') ttt=-1,j++;
                while(j<len&&s[j]!=' ') num=num*10+s[j]-'0',j++;
                while(j<len&&s[j]==' ') j++;
                while(j<len&&s[j]==',') j++;
                num*=ttt;
                if(!id[name]) id[name]=++cn;
                int x=id[name];
                if(p=="<") a[i].R[x]=min(a[i].R[x],num-1);
                else if(p=="<=") a[i].R[x]=min(a[i].R[x],num);
                else if(p==">") a[i].L[x]=max(a[i].L[x],num+1);
                else if(p==">=") a[i].L[x]=max(a[i].L[x],num);
                else if(p=="==") a[i].L[x]=max(a[i].L[x],num),a[i].R[x]=min(a[i].R[x],num);
                //cout<<"j="<<j<<" len="<<len<<endl;
            }
            REP(j,1,30) if(a[i].L[j]>a[i].R[j]) a[i].kong=1;
            vector<int> ans;
            REP(j,1,i-1){
                if(a[j].kong||a[i].kong) continue;
                bool has=1;
                REP(k,1,30){
                    if(a[i].L[k]>a[j].R[k]||a[j].L[k]>a[i].R[k]){
                        has=0;break;
                    }
                }
                if(has) ans.push_back(j);
            }
            if(a[i].kong||(int)ans.size()==0) puts("unique");
            else{
                for(int j=0;j<ans.size();j++){
                    printf("%d",ans[j]);
                    if(j!=(int)ans.size()-1) printf(" ");
                    else printf("\n");
                }
            }
        }
        //REP(i,1,cn) cout<<a[3].L[i]<<" "<<a[3].R[i]<<" "<<a[3].kong<<endl;
    }
    return 0;
}
View Code

 

posted @ 2016-05-16 17:25  __560  阅读(423)  评论(0编辑  收藏  举报