北京培训 DAY7
早上讲COCI,即克罗地亚的IOI选拔赛的题
一下子就蠢了一早上 = = 发现好多题都是在学校里的NOIP模拟赛中做到过的 到底学校的NOIP模拟赛是什么难度啊啊啊啊啊- -
具体题目就不说了
下午是ACM赛制的一次比赛 挺有趣的 据说前三名的队伍有奖品 五个小时十道题
一开始题目的数据没有配好 怎么交都只要编译通过就是AC 开始两个小时还以为自己写的都是对的= = 后来改会来再交发现WA了一万道 只好慢慢改 不过最后还是有前三 感觉不错
就这样吧
北京培训 DAY6
啦啦啦 种太阳~~~
早上题目据说是可选不做的 = = 但是我还是去写了(我真是无聊)
第一题
莫比乌斯反演+找规律 题解在这里 自己看吧
链接:
第二题
给一个字符串集合 支持将集合中的串i删除或加入 查询给定一个串S 这个集合中的字符串在S中出现次数
写了一早上没调出来 到了中午才终于弄出来 = =
对集合建一个AC-automaton(这里每个点的结尾标记不可合并)然后再以fail指针连边新建一棵fail树 每个点的权值为AC-automaton中的标记值 然后每次转移时访问这个结点在fail树中对应结点到根路径上的权值和 以DFS序+树状数组维护 完成~
贴个代码纪念一下
#include <iostream> #include <cstdlib> #include <cstring> #include <string> #include <cstdio> #include <queue> using namespace std; const int Size=26,maxn=1000086; int n,m,f[maxn][2],num,ans,head[maxn*2],num_edge,seq[maxn*2],now_node,len ,corres[maxn][2],val[maxn],sum[maxn*4],end[maxn]; char s[maxn],order; bool visit[maxn],use[maxn]; struct AC_automaton { struct Node { int next[Size+1]; int fail; int father; int val; int flag; }node[maxn]; int num_node,root,qs[maxn]; AC_automaton() { num_node=root=0; node[root].val=0; } int get_num(char a) { return int(a-'a'+1); } void insert(int pos) { int now_pos,len_s=strlen(s); now_pos=0; for(int i=0;i<len_s;i++) { if(!node[now_pos].next[get_num(s[i])]) { node[now_pos].next[get_num(s[i])]=++num_node; node[num_node]=(Node){{0},0,now_pos,get_num(s[i]),0}; } now_pos=node[now_pos].next[get_num(s[i])]; } node[now_pos].flag++; end[pos]=now_pos; } int get_fail(int now,int val) { if(node[now].next[val])return node[now].next[val]; if(now==0)return 0; int tmp=get_fail(node[now].fail,val); return tmp; } void build_fail() { int tmp,l=1,r=0; qs[++r]=0; while(l<=r) { tmp=qs[l++]; if(!node[tmp].father)node[tmp].fail=0; else node[tmp].fail=get_fail(node[node[tmp].father].fail,node[tmp].val); for(int i=1;i<=Size;i++) if(node[tmp].next[i]) qs[++r]=node[tmp].next[i]; } } int get_next_node(int now,int val) { while((now!=0)&&(!node[now].next[val])) now=node[now].fail; if(node[now].next[val]!=0)return node[now].next[val]; return 0; } }T; struct Edge { int next; int to; }edge[maxn*2]; void add_edge(int from,int to) { edge[++num_edge].next=head[from]; edge[num_edge].to=to; head[from]=num_edge; } struct T_T { int now; int next; }istack[maxn],tmp; void get_seq() { int top=1; istack[1].now=1; istack[1].next=head[1]; seq[++len]=0; visit[1]=1; corres[0][0]=1; while(top) { tmp=istack[top--]; if(tmp.next==0) { corres[tmp.now-1][1]=len+1; continue; } visit[edge[tmp.next].to]=1; istack[++top]=(T_T){tmp.now,edge[tmp.next].next}; istack[++top]=(T_T){edge[tmp.next].to,head[edge[tmp.next].to]}; seq[++len]=edge[tmp.next].to-1; corres[edge[tmp.next].to-1][0]=len; } } inline int lowbit(int u){return (u&(-u));} void add_num(int pos,int num) { for(int i=pos;i<=maxn*2;i+=lowbit(i))sum[i]+=num; } int get_sum(int pos) { int tmp=0; for(int i=pos;i>0;i-=lowbit(i))tmp+=sum[i]; return tmp; } int main() { scanf("%d %d",&m,&n); for(int i=1;i<=n;i++) { scanf("%s",s); T.insert(i); } T.build_fail(); for(int i=1;i<=T.num_node;i++) { add_edge(T.node[i].fail+1,i+1); val[i]=T.node[i].flag; } for(int i=1;i<=n;i++)use[i]=1; get_seq(); for(int i=0;i<=T.num_node;i++) { add_num(corres[i][0],val[i]); add_num(corres[i][1],-val[i]); } for(int i=1;i<=m;i++) { scanf("\n%c",&order); if(order=='-') { scanf("%d",&num); if(use[num]) { use[num]=0; val[end[num]]--; add_num(corres[end[num]][0],-1); add_num(corres[end[num]][1],1); } } else if(order=='+') { scanf("%d",&num); if(!use[num]) { use[num]=1; val[end[num]]++; add_num(corres[end[num]][0],1); add_num(corres[end[num]][1],-1); } } else { ans=now_node=0; scanf("%s",s); len=strlen(s); for(int i=0;i<len;i++) { now_node=T.get_next_node(now_node,s[i]-'a'+1); ans+=get_sum(corres[now_node][0]); } printf("%d\n",ans); } } return 0; }
然后是第三题 据说是三题中最简单的 是一个DP
题目就贴链接算了:
题解也贴链接算了:
下午讲了下题解 结束
————————The End——————————