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; }
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; }
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; }
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; }
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; }
没有AC不了的题,只有不努力的ACMER!