集训Day1
雅礼集训2017Day1的题
感觉上不可做实际上还挺简单的吧
T1
区间加 区间除法向下取整
查询区间和 区间最小值
大力上线段树,把除法标记推到底,加法标记就是按照线段树的来
先拿30
然后60的数据随机不知道该怎么做
开始YY
那个“向下取整”的tag并不能累加
所以考虑转化
除法->减法
如果一个区间要减的都是一样的数,直接减就行了,如果不一样,就递归下去,反正1个数肯定减的是一样的
本来想拿60,结果A了
T2
n*n的棋盘(n = 1000)每次把找一行,把它的颜色序列copy下来涂到一列上
问最少多少次能把整个棋盘涂黑
首先 全白肯定无解
其次 只要把一行涂黑 之后涂n次就可以了
然后 大力模拟发现并没有比这个优的策略
于是一顿乱搞
我们枚举第i行,假装要把他弄成全1的。
设第i行的0的数量为cc[i],那么考虑第i列是否含有1,如果含有1那么就可以用含有1的那列的那行给第i行所有0的地方赋值,需要cc[i]步。
如果第i列不含有1,我们要花1次操作给第i列搞个1出来,所以答案是cc[i]+1步。
每行取个min
听说是签到题...数据极水 被各种对的不对的做法爆切
T3
令 s 与 w 为两字符串,定义:
- $w[l,r]$ 表示字符串 $w$ 在区间 $[l,r]$中的子串;
- $w$ 在 $s $中出现的频率定义为$w$ 在 $s$ 中出现的次数;
- $f(s,w,l,r)$表示 $w[l,r]$ 在 $s$ 中出现的频率。
比如 $f(ababa,aba,1,3)=2$。
现在给定串 $s$,$m$个区间 $[l,r] $ 和长度 $k$ ,你要回答 $q$ 个询问,每个询问给你一个长度为 $k$ 的字符串 $w$ 和两个整数 $a,b$,求:
$\sum\limits_{i = a} ^ b f(s, w, l_i, r_i)$
重要条件
$\sum w_i$ 是个定值
所以很eazy看了题解后想到要写两种做法
首先考虑k小的情况
这种情况我们可以用SAM暴力处理出right集合计算每一个子串在当前串出现的次数
我的暴力永远比别人慢系列
用莫队可以把O(n^2 k ^2)优化到(n sqrt n k ^2)写写写
k大时可以考虑在SAM的parent树上跑一个倍增
暴力记前缀然后倍增往上跳找到后缀
这样遍历每个子串就可以做了
这是什么完全不可做的毒瘤题啊妈妈带我回家吧我不学OI了
嗯 抬头 微笑
感觉没看到签到题有点亏...想T1想了2个小时有点不应该
然后1个小时迅速切T2
T3就没时间想了只能n^3的KMP
最后100 + 100 + 30
感觉拿了个大众分?
2018.6.6upd
代码写完了 贴一下
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstring> #include<algorithm> #define LL long long using namespace std; inline int read() { int x = 0,f = 1;char ch = getchar(); for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f; for(;isdigit(ch);x = 10 * x + ch - '0',ch = getchar()); return x * f; } inline LL Lread() { LL x = 0,f = 1;char ch = getchar(); for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f; for(;isdigit(ch);x = 10 * x + ch - '0',ch = getchar()); return x * f; } const int maxn = 1e5 + 10; int n,m; LL a[maxn]; LL minx[maxn << 2],sum[maxn << 2],maxx[maxn << 2],add[maxn << 2]; #define ls (x << 1) #define rs ((x << 1) | 1) inline void pushup(int x){minx[x] = min(minx[ls],minx[rs]);sum[x] = sum[ls] + sum[rs];maxx[x] = max(maxx[ls],maxx[rs]);} inline void pushdown(int x,int l,int r) { if(add[x]) { add[ls] += add[x];add[rs] += add[x]; int mid = (l + r) >> 1; sum[ls] += add[x] * (mid - l + 1);sum[rs] += add[x] * (r - mid); minx[ls] += add[x];minx[rs] += add[x];maxx[ls] += add[x];maxx[rs] += add[x]; add[x] = 0; } } inline void build(int x,int l,int r) { if(l == r) { maxx[x] = minx[x] = sum[x] = a[l]; return; } add[x] = 0; int mid = (l + r) >> 1; build(ls,l,mid);build(rs,mid + 1,r); pushup(x); } inline void update1(int x,int l,int r,int L,int R,int c) //Add { if(L <= l && r <= R) { add[x] += c; sum[x] += (r - l + 1) * c; minx[x] += c;maxx[x] += c; return; } pushdown(x,l,r);int mid = (l + r) >> 1; if(L <= mid)update1(ls,l,mid,L,R,c); if(R > mid)update1(rs,mid + 1,r,L,R,c); pushup(x); } inline void update2(int x,int l,int r,int L,int R,int d) //Div { if(L <= l && r <= R) { if(minx[x] == maxx[x] || ((maxx[x] % d == 0) && (maxx[x] - 1 == minx[x]))) { LL delta = maxx[x] - (LL)floor((1.0 * maxx[x] / d)); add[x] -= delta; minx[x] -= delta;maxx[x] -= delta; sum[x] -= 1LL *delta * (r - l + 1); return; } //return; } pushdown(x,l,r);int mid = (l + r) >> 1; if(L <= mid)update2(ls,l,mid,L,R,d); if(R > mid)update2(rs,mid + 1,r,L,R,d); pushup(x); } inline LL query1(int x,int l,int r,int L,int R) //Min { if(L <= l && r <= R)return minx[x]; pushdown(x,l,r); int mid = (l + r) >> 1; LL ans = 21474832333333LL; if(L <= mid)ans = min(ans,query1(ls,l,mid,L,R)); if(R > mid)ans = min(ans,query1(rs,mid + 1,r,L,R)); return ans; } inline LL query2(int x,int l,int r,int L,int R) //Sum { if(L <= l && r <= R)return sum[x]; pushdown(x,l,r);int mid = (l + r) >> 1;LL ans = 0; if(L <= mid)ans += query2(ls,l,mid,L,R); if(R > mid)ans += query2(rs,mid + 1,r,L,R); return ans; } int main() { n = read(),m = read(); for(int i=1;i<=n;i++)a[i] = Lread(); build(1,1,n); while(m--) { int opt = read(),l = read() + 1,r = read() + 1; if(opt == 1) { int c = read(); update1(1,1,n,l,r,c); } if(opt == 2) { int d = read(); update2(1,1,n,l,r,d); } if(opt == 3) { LL ans = query1(1,1,n,l,r); printf("%lld\n",ans); } if(opt == 4) { LL ans = query2(1,1,n,l,r); printf("%lld\n",ans); } } return 0;
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstring> #include<algorithm> #define LL long long using namespace std; inline int read() { int x = 0,f = 1;char ch = getchar(); for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f; for(;isdigit(ch);x = 10 * x + ch - '0',ch = getchar()); return x * f; } int n,ac,ans; int cr[1010],cc[1010]; char ch[1010]; int main() { n = read(); for(int i=1;i<=n;i++) { scanf("%s",ch + 1); for(int j=1;j<=n;j++) { if(ch[j] == '#')ac++; if(ch[j] == '.')cr[i] ++,cc[j]++; } } if(!ac){puts("-1");return 0;} for(int i=1;i<=n;i++)if(cc[i])++ans; int _Ma = 2 * n + 1; for(int i=1;i<=n;i++)_Ma = min(_Ma,cr[i] + (cc[i] == n)); cout<<ans + _Ma<<endl; }
#include<bits/stdc++.h> #define LL long long using namespace std; const int LIM = 555; inline int read() { int x=0,f=1;char ch; for(ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')f=-f; for(;isdigit(ch);ch=getchar())x=10*x+ch-'0'; return x*f; } const int maxn = 210010; int n,m,k,q; char s[maxn]; struct SAM { int tr[maxn][26],fa[maxn],len[maxn],size[maxn]; int ST[maxn][21],id[maxn],Cnt[maxn]; int last,p,np,q,nq,cnt,rt; SAM(){last = ++cnt; rt = 1;} inline void extend(int c) { p = last, np = last = ++cnt, len[np] = len[p] + 1;size[np] = 1; while(!tr[p][c] && p) tr[p][c] = np, p = fa[p]; if(!p) fa[np] = rt; else { q = tr[p][c]; if(len[q] == len[p] + 1) fa[np] = q; else { nq = ++cnt; len[nq] = len[p] + 1; memcpy(tr[nq],tr[q],sizeof(tr[q])); fa[nq] = fa[q]; fa[q] = fa[np] = nq; while(tr[p][c] == q) tr[p][c] = nq,p = fa[p]; } } } inline void buildsize() { for(int i=1;i<=cnt;i++)Cnt[len[i]]++; for(int i=1;i<=n;i++)Cnt[i] += Cnt[i-1]; for(int i=1;i<=cnt;i++)id[Cnt[len[i]]--] = i; for(int i=cnt;i>=1;i--)size[fa[id[i]]] += size[id[i]]; } inline void STLCA() { for(int i=1;i<=cnt;i++)ST[i][0]=fa[i]; for(int i=1;i<21;i++)for(int j=1;j<=cnt;j++)ST[j][i]=ST[ST[j][i-1]][i-1]; } inline int query(int x,int va) { if(len[x] < va)return 0; for(int i=20;i>=0;i--) if(len[ST[x][i]] >= va)x = ST[x][i]; return size[x]; } inline int trans(int &now,int v,int x) { if(tr[now][x]) { now=tr[now][x]; return v + 1; } while(now && !tr[now][x])now=fa[now]; v = len[now]; if(tr[now][x])v++; now = tr[now][x]; if(now == 0)now = 1; return v; } }sam; //快来跟我写后缀自动机 写一下 调一年 struct Xianzhi{int l,r;}req[maxn]; namespace Modui_ksmall { struct Query { int l,r,id; bool operator < (const Query &a)const { if((l / LIM) == (a.l / LIM))return r < a.r; return (l / LIM) < (a.l / LIM); } }qs[maxn]; LL res[maxn],ans[LIM][LIM]; char w[maxn][LIM]; void solve() { for(int i=1;i<=q;i++) { scanf("%s",w[i] + 1); qs[i].l = read() + 1;qs[i].r = read() + 1;qs[i].id = i; } sort(qs + 1,qs + q + 1); int l = 0,r = 0; for(int i=1;i<=q;i++) { for(;l < qs[i].l;l++)ans[req[l].l][req[l].r]--; for(;l > qs[i].l;l--)ans[req[l - 1].l][req[l - 1].r]++; for(;r < qs[i].r;r++)ans[req[r + 1].l][req[r + 1].r]++; for(;r > qs[i].r;r--)ans[req[r].l][req[r].r]--; for(int s=1;s<=k;s++) { int now = 1; for(int t=s;t<=k;t++) { now=sam.tr[now][w[qs[i].id][t] - 'a']; if(now)res[qs[i].id] += (LL) sam.size[now] * ans[s][t]; } } } for(int i=1;i<=q;i++)printf("%lld\n",res[i]); } } namespace Beizeng_klarge { vector<LL> vec[maxn]; char w[maxn]; int v; void solve() { LL ans;int a,b; while(q--) { ans = 0; scanf("%s%d%d",w + 1,&a,&b);a++,b++; for(int i=a;i<=b;i++)vec[req[i].r].push_back(req[i].r - req[i].l + 1); int now = 1,maxlen = 0; for(int i=1;i<=k;i++) { maxlen = sam.trans(now,maxlen,w[i] - 'a'); for(auto j : vec[i]) if(maxlen >= j)ans += sam.query(now,j); vec[i].clear(); } printf("%lld\n",ans); } } } int main() { n = read(),m = read(),q = read(),k = read(); scanf("%s",s + 1);for(int i=1;i<=n;i++)sam.extend(s[i] - 'a'); sam.buildsize(),sam.STLCA(); for(int i=1;i<=m;i++)req[i].l = read() + 1,req[i].r = read() + 1; if(k < LIM)Modui_ksmall::solve(); else Beizeng_klarge::solve(); }