是时候开刷NOI了
整天挨着毛爷爷,压力好大。。
看毛爷爷即将炖完NOI,我的确也该刷了
原则是从头到尾自己想(虽然看了一次题解),可以不A掉。
NOI2009
day1:
T1
题目略神,我还是不讲了。。。(就这题我WA了好多遍 TAT)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bitset>
#include <vector> #define N 20010 using namespace std; struct edge{
int x,to;
}E[N<<]; int n,a[N],pre[N],totE,g[N];
bitset<N> v;
vector<int> G[N]; #define p G[x][i] void ade(int x,int y){
G[x].push_back(y);
} int find(int x){
v[x]=;
int len=G[x].size();
for(int i=;i<len;i++)
if(!v[p]){
v[p]=;
if(!pre[p]||find(pre[p])){
pre[p]=x; pre[x]=p;
return ;
}
}
return ;
} int main(){
freopen("transform.in","r",stdin);
freopen("transform.out","w",stdout);
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=;i<=n;i++){
if(i-a[i]>=) G[i].push_back(n+i-a[i]);
else G[i].push_back(n+i-a[i]+n);
if(i+a[i]<=n) G[i].push_back(n+i+a[i]);
else G[i].push_back(i+a[i]);
}
for(int i=;i<=n;i++) sort(G[i].begin(),G[i].end());
int ans=;
for(int i=n;i>=;i--){
v.reset();
if(find(i)) ans++;
}
if(ans!=n){
puts("No Answer");
}
else{
for(int i=;i<n;i++) printf("%d ",pre[i]-n-);
printf("%d\n",pre[n]-n-);
}
return ;
}
T2
脑补一下,这个应该是一个单峰函数,果断三分。
爆long long QAQ,这要是NOI我就被坑死啦,long double过。
#include <cstdio>
#include <cstring>
#include <algorithm> #define LL long long
#define N 200010
#define LD long double using namespace std; int n,P;
int len[N],pre[N];
LL L;
LD f[N];
char S[N][]; LD qpow(LD x,LL n){
LD ans=;
for(;n;n>>=,x*=x)
if(n&) ans*=x;
return ans;
} LD Abs(LL x){
if(x<) return -(LD)x;
return (LD)x;
} LD F(int i,int j){
return f[j]+
qpow(Abs(L-(len[i]-len[j]+i-j-1LL)),P);
} int find(int i){
int l=,r=i-,m1,m2;
while(r-l>){
m1=l+(r-l)/;
m2=r-(r-l)/;
if(F(i,m1)<F(i,m2)) r=m2;
else l=m1;
}
LD ans=F(i,);
int pos=;
for(int t=l;t<=r;t++)
if(F(i,t)<ans){
ans=F(i,t);
pos=t;
}
return pos;
} void print(int t){
if(pre[t]) print(pre[t]);
for(int i=pre[t]+;i<t;i++){
printf("%s ",S[i]);
}
printf("%s\n",S[t]);
} int main(){
freopen("noi09_poet.in","r",stdin);
freopen("noi09_poet.out","w",stdout);
int T;
scanf("%d",&T);
while(T--){
scanf("%d %lld %d",&n,&L,&P);
for(int i=;i<=n;i++){
scanf("%s",S[i]);
len[i]=strlen(S[i]);
}
for(int i=;i<=n;i++) len[i]+=len[i-];
memset(f,,sizeof(f));
f[]=;
for(int i=;i<=n;i++){
int j=find(i);
f[i]=f[j]+qpow(Abs(L-(len[i]-len[j]+i-j-1LL)),P);
pre[i]=j;
}
if(f[n]>1e18){
puts("Too hard to arrange");
}
else{
printf("%lld\n",(LL)(f[n]));
print(n);
}
puts("--------------------");
}
return ;
}
T3
QAQ好难,膜毛爷爷。
首先所谓 (频度 x 深度) 我们可以每过一层就加上当前的频度得到答案。
利用先序遍历的特殊性质(TAT 其实想到这个就差不多了),考虑dp。
f[i][j][k] 表示先序遍历从 i 到 j 作为一个子树(可能多个),而且满足所有权值小于等于k的最小花费。
转移分两种情况,修改当前root权值,修改子树权值。
$O(n^4)$ dp即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream> #define N 80
#define LL long long
#define INF 0x7f7f7f7f7f7f7f7fLL
#define debug(x) cout<<#x<<" = "<<x<<endl; using namespace std; int n,tot0;
int a[N],b[N],c[N],X[N];
LL K;
LL dp[N][N][N];
LL s[N][N]; /*
O(n^5) f[i][j][k]
i到j之间的所有数值大于k,
消灭当前点 f[i][j][k] = min{ f[i][p-1][k] + f[p+1][j][k] + s[i][j] + K }
不消灭当前点 f[i][j][k] = min{ f[i][p-1][b[p]] + f[p+1][j][b[p]] + s[i][j] }
*/ LL F(int i,int j,int k){
if(i>j) return ;
// printf("%d %d %d\n",i,j,k);
if(dp[i][j][k]) return dp[i][j][k];
if(i==j) return dp[i][j][k]=b[i]<k ?K+c[i]:c[i];
dp[i][j][k]=INF;
for(int p=i;p<=j;p++){ //改当前点权
dp[i][j][k]=min(dp[i][j][k],F(i,p-,k) + F(p+,j,k) + s[i][j] + K);
if(b[p]>=k){ //不改当前点权
dp[i][j][k]=min(dp[i][j][k],F(i,p-,b[p]) + F(p+,j,b[p]) + s[i][j]);
}
}
return dp[i][j][k];
} void init(){
for(int i=;i<n;i++)
for(int j=i+;j<=n;j++)
if(a[i]>a[j]){
swap(a[i],a[j]);
swap(b[i],b[j]);
swap(c[i],c[j]);
}
sort(X+,X+n+);
tot0=;
for(int i=;i<=n;i++)
if(X[i]!=X[i-]) X[++tot0]=X[i];
for(int i=;i<=n;i++)
b[i]=lower_bound(X+,X+tot0+,b[i])-X;
for(int i=;i<=n;i++){
s[i][i]=c[i];
for(int j=i+;j<=n;j++)
s[i][j]=s[i][j-]+c[j];
}
} int main(){
freopen("treapmod.in","r",stdin);
freopen("treapmod.out","w",stdout);
scanf("%d%d",&n,&K);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
for(int i=;i<=n;i++){
scanf("%d",&b[i]);
X[i]=b[i];
}
for(int i=;i<=n;i++) scanf("%d",&c[i]);
init();
LL ans=INF;
for(int i=;i<=n;i++){
ans=min(ans,F(,n,b[i]));
}
cout<<ans<<endl;
return ;
}
day2
T1:
裸网络流,注意要拓扑一下,还要判环,环内的植物不能碰。
T2:
又是一道$dp$,思路很神(TAT 实在不会,看了题解)。
就是将 平方和 转化为结果相同的方案对数(自己也算)
然后裸dp上。
#include <cstdio>
#include <cstring>
#include <algorithm> #define N 510
#define mod 1024523 using namespace std; /*
f[i][j][k]表示上面取了上i下j,上k。
*/ char S1[N],S2[N];
int f[N][N][N],n,m; int add(int a,int b){
if(a+b<mod) return a+b;
return a+b-mod;
} int main(){
freopen("ballb.in","r",stdin);
freopen("ballb.out","w",stdout);
scanf("%d%d%s%s",&n,&m,S1,S2);
reverse(S1,S1+n);
reverse(S2,S2+m);
f[][][]=;
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
for(int k=;k<=n;k++){
if(!f[i][j][k]) continue;
int l = i+j-k;
if(l<) break;
//printf("f[%d][%d][%d] = %d\n",i,j,k,f[i][j][k]);
if(i<n && k<n && S1[i]==S1[k]){
f[i+][j][k+] = add(f[i+][j][k+],f[i][j][k]);
}
if(i<n && l<m && S1[i]==S2[l]){
f[i+][j][k] = add(f[i+][j][k],f[i][j][k]);
}
if(j<m && k<n && S2[j]==S1[k]){
f[i][j+][k+] = add(f[i][j+][k+],f[i][j][k]);
}
if(j<m && l<m && S2[j]==S2[l]){
f[i][j+][k] = add(f[i][j+][k],f[i][j][k]);
}
}
}
}
printf("%d\n",f[n][m][n]);
return ;
}
T3:
很好的提交答案题。
做好了70分吧。
NOI 2008
TAT QAQ QWQ TWT
题出这么难也是醉了。
day1:
T1
找环然后分类讨论,情况不多就三种。
可是好多细节呀,蒟蒻我是调不出来的。
#include <iostream>
#include <cstdio>
#include <cstring> using namespace std; template<typename T> T abs(T x){
if(x>) return x;
return -x;
}
template<typename T> T gcd(T x, T y){
for(T t;x!=;t=x,x=y%x,y=t);
return y;
} const int Maxn =;
const int Maxm =; struct edge{
int to,x,v;
}Edges[Maxm]; int totE=,head[Maxn]; void addedge(int u,int v,int w){
Edges[++totE]=(edge){head[u],v,w};
head[u]=totE;
} int n,m,ans=,d[Maxn],maxt,mint;
bool vis[Maxn]; void dfs(int x){
vis[x]=;
for(int i=head[x];i;i=Edges[i].to){
int p=Edges[i].x;
if(vis[p]) ans=gcd(ans,abs(d[x]+Edges[i].v-d[p]));
else d[p]=d[x]+Edges[i].v,dfs(p);
}
} void find(int x){
vis[x]=;
maxt=max(maxt,d[x]);
mint=min(mint,d[x]);
for(int i=head[x];i;i=Edges[i].to){
int p=Edges[i].x;
if(!vis[p]) d[p]=d[x]+Edges[i].v,find(p);
}
} int main(){
freopen("party2008.in","r",stdin);
freopen("party2008.out","w",stdout);
scanf("%d%d",&n,&m);
int u,v,tmp;
for(int i=;i<=m;i++){
scanf("%d%d",&u,&v);
addedge(u,v,);
addedge(v,u,-);
}
for(int i=;i<=n;i++)
if(!vis[i]) d[i]=,dfs(i);
if(ans){
for(tmp=;tmp<ans&&ans%tmp;tmp++);
//cout<<"case 1\n";
}
else{
memset(vis,,sizeof(vis));
tmp=;
for(int i=;i<=n;i++)
if(!vis[i]){
maxt=mint=d[i]=;
find(i);
ans+=maxt-mint+;
}
}
if(ans<) ans=tmp=-;
printf("%d %d\n",ans,tmp);
return ;
}
T2
相对温暖的一道题。
可以发现一个条件:答案是 $O(logn)$ 级的(为啥我也不知道)。
然后变成了经典问题,直接枚举【不便利值】树形dp方案数,$f[i][j]$表示 $i$ 这个点向下连 $j$ 条边的方案数,直到方案数不为0为止。
注意0和mod后为0不同,因为要判断是否有方案,所以如果是因为mod而变成的0记做mod。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue> #define Maxn 100010
typedef long long LL; using namespace std; int n,m,Q,dep[Maxn];
LL f[Maxn][][];
vector<int> G[Maxn]; /*
link = f[p][j][0] + f[p][j][1]
not_link = f[p][j-1][0] + f[p][j-1][1] + f[p][j-1][2] f[i][j][2] = f[i][j][2] * not_link + f[i][j][2]
f[i][j][1] = f[i][j][1] * not_link + f[i][j][0] * link
f[i][j][0] = f[i][j][0] * not_link
*/ bool find_circle(int x,int tp){
for(int i=;i<G[x].size();i++){
if(G[x][i]==tp) continue;
if(dep[G[x][i]]) return ;
dep[G[x][i]]=dep[x]+;
if(find_circle(G[x][i],x)) return ;
}
return ;
} bool not_a_tree(int x){
dep[x]=;
if(find_circle(x,)) return ;
for(int i=;i<=n;i++)
if(!dep[i]) return ;
return ;
} LL Mod(LL x){
if(x==) return ;
if(x%Q==) return Q;
return x%Q;
} LL dp(int x,int tp,int j){
f[x][j][]=f[x][j][]=0LL;
f[x][j][]=1LL;
for(int i=;i<G[x].size();i++){
int p=G[x][i];
if(p==tp) continue;
dp(p,x,j);
int not_link=,link=;
link =Mod(f[p][j][]+f[p][j][]);
if(j>) not_link =Mod(f[p][j-][]+Mod(f[p][j-][]+f[p][j-][]));
f[x][j][] =Mod(f[x][j][]*not_link)+Mod(f[x][j][]*link);
f[x][j][] =Mod(f[x][j][]);
f[x][j][] =Mod(f[x][j][]*not_link)+Mod(f[x][j][]*link);
f[x][j][] =Mod(f[x][j][]);
f[x][j][] =Mod(f[x][j][]*not_link);
}
return Mod(f[x][j][]+Mod(f[x][j][]+f[x][j][]));
} int main(){
freopen("design.in","r",stdin);
freopen("design.out","w",stdout);
scanf("%d%d%d",&n,&m,&Q);
int u,v,tmp=;
LL ans=;
for(int i=;i<=m;i++){
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
if(n!=m+||not_a_tree()){
puts("-1\n-1");
return ;
}
while(ans<=) ans=dp(,,tmp++);
printf("%d\n%lld\n",tmp-,ans==Q? :ans);
return ;
}
T3
蒟蒻表示自己图论超级渣。
以前看题解过了,现在还不懂。
day2
T1
妈呀,基环外向树上dp,醉了,还是概率dp。
用贪心水到了40分,好像有人说可以70分,咦是我交的题库上的数据太强了吗。
T2
day2的温暖题。
QAQ 但是好寒冷。
直接转化一下,二维树状数组。
#include <iostream>
#include <cstdio>
#include <cstring> #define Maxn 1010
#define Maxc 1000010 typedef int Se[Maxn*][Maxn<<]; using namespace std; int n,T,len,m;
Se a,b;
struct Cloud{
int t,p;
}clou[Maxc]; void Add(Se a,int x,int y,int d){
for(int i=x+;i<len*+;i+=i&-i)
for(int j=y+;j<(len<<)+;j+=j&-j)
a[i][j]+=d;
} int Ask(Se a,int x,int y){
int ans=;
for(int i=x+;i;i-=i&-i)
for(int j=y+;j;j-=j&-j)
ans+=a[i][j];
return ans;
} void Add1(int x,int y,int d){
Add(a,x,x+y,d);
} void Add2(int x,int y,int d){
Add(b,x-len,y-x+m,d);
} void update(int c,int d){
int t=clou[c].t,p=clou[c].p;
Add1(t,p,d);
if(t<=len) Add1(t+n,p,d);
Add2(t+n,p,d);
if(t>=len) Add2(t,p,d);
} int Ask1(int x0,int y0,int x1,int y1){
return Ask(a,x1,x1+y1) - Ask(a,x0-,x1+y1)
- Ask(a,x1,x0+y0-) + Ask(a,x0-,x0+y0-);
} int Ask2(int x0,int y0,int x1,int y1){
return Ask(b,x1-len,y1-x1+m) - Ask(b,x0-len-,y1-x1+m)
- Ask(b,x1-len,y0-x0+m-) + Ask(b,x0-len-,y0-x0+m-);
} int query(int t,int L,int R){
int ans=Ask1(t,L,t+R,len),d=len==R;
if(!R) return ans;
return ans+=Ask2(t+n-R+d,L-R+d,t+n-,len+R-);
} int main(){
freopen("noi2008_candy.in","r",stdin);
freopen("noi2008_candy.out","w",stdout);
scanf("%d%d",&T,&len);
n=*len; m=*n;
for(int i=;i<=T;i++){
int K,t,c,L,R,d;
scanf("%d%d",&K,&t);
t%=n;
if(K==){
scanf("%d%d%d%d",&c,&L,&R,&d);
clou[c].t=(t-d*L+n)%n;
clou[c].p=R-L;
update(c,);
}
else if(K==){
scanf("%d%d",&L,&R);
printf("%d\n",query(t,L,R));
}
else{
scanf("%d",&c);
update(c,-);
}
}
return ;
}
T3
提交答案题,还没做
继续
NOI2010
Day1
T1:能量采集:SB题,随便搞
#include <cstdio>
#include <cstring>
#include <algorithm> #define LL long long
#define Maxn 100010 using namespace std; LL n,m,ans;
LL phi[Maxn]={,,}; int main(){
freopen("energy2010.in","r",stdin);
freopen("energy2010.out","w",stdout);
scanf("%lld%lld",&n,&m);
if(n<m) swap(n,m);
for(int i=;i<=m;i++){
if(phi[i]) continue;
for(int j=i;j<=m;j+=i){
if(!phi[j]) phi[j]=j;
phi[j]=phi[j]*(i-)/i;
}
}
for(int i=;i<=m;i++){
ans+=(n/i)*(m/i)*phi[i];
}
ans=(ans-m*n)*+m*n;
printf("%lld\n",ans);
return ;
}
T2:超级钢琴。
区间裂解,就是找到前K大的子区间和
ST+堆,随便搞。
#include <cstdio>
#include <queue>
using namespace std; typedef long long LL; const int maxn = ; struct Node {
LL x; int l, r, i;
bool operator < (const Node &A) const {
return x < A.x;
}
};
priority_queue<Node> pq; int n, K, L, R;
LL S[maxn];
int rmq[][maxn]; void RMQ_init() {
int k = ; for (; ( << k+) < n+; ++ k);
for (int i = ; i <= n; ++ i) rmq[][i] = i; for (int j = ; j <= k; ++ j)
for (int i = ; i+(<<j)- <= n; ++ i) {
int p = rmq[j-][i], q = rmq[j-][i+(<<j-)];
rmq[j][i] = S[p] < S[q] ? p : q;
}
}
int RMQ(int l, int r) {
int z = r-l+;
int k = ; for (; ( << k+) < z; ++ k);
int p = rmq[k][l], q = rmq[k][r-(<<k)+];
return S[p] < S[q] ? p : q;
} int main() {
freopen("piano.in", "r", stdin);
freopen("piano.out", "w", stdout); scanf("%d%d%d%d", &n, &K, &L, &R); for (int i = ; i <= n; ++ i) {
int x; scanf("%d", &x);
S[i] = S[i-] + x;
}
RMQ_init(); for (int i = ; i <= n; ++ i) {
int a = i-R, b = i-L; if (a < ) a = ;
if (b >= ) pq.push((Node){S[i] - S[RMQ(a, b)], a, b, i});
} LL res = ;
while (K --) {
if (pq.empty()) break;
Node x = pq.top(); pq.pop();
res += x.x; int t = RMQ(x.l, x.r);
if (x.l <= t-) pq.push((Node){S[x.i] - S[RMQ(x.l, t-)], x.l, t-, x.i});
if (t+ <= x.r) pq.push((Node){S[x.i] - S[RMQ(t+, x.r)], t+, x.r, x.i});
}
printf("%lld\n", res); fclose(stdin); fclose(stdout);
return ;
}
T3:海拔
不想写对偶图,懒癌犯了,dinic 80何必呢。
Day2
T1:航空管制
很神,但是是贪心。拓扑一下然后直接贪心。
在不看题解下拿了80(二分答案+乱搞)
T2:旅行路线
很懒,裸插头dp,不想捉。
NOI2011
Day1
T1:兔农
很久以前过的了,忘了。
T2:智能车比赛
很SB的水题,最短路,建图叉积一下,貌似我写麻烦了。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib> #define LL long long
#define sqr(x) ((x)*(x))
#define N 8010
#define p E[i].x using namespace std; struct edge{
int x,to;
long double v;
}E[]; struct node{
int x,y,id; void print(){
printf("(%d,%d)",x,y);
} void scan(){
scanf("%d%d",&x,&y);
}
}S,T,P[]; int tot;
queue<int> q; struct road{
node Lu,Ld,Ru,Rd; void scan(){
Ld.scan();
Ru.scan();
Lu=(node){Ld.x,Ru.y};
Rd=(node){Ru.x,Ld.y};
Ld.id=++tot; P[tot]=Ld;
Lu.id=++tot; P[tot]=Lu;
Rd.id=++tot; P[tot]=Rd;
Ru.id=++tot; P[tot]=Ru;
}
}L[N]; int n,totE;
int g[N];
double V;
long double dis[N];
bool v[N]; double dist(node a,node b){
return sqrt(sqr((LL)(a.x-b.x))+sqr((LL)(a.y-b.y)));
} LL cross(node a,node b,node c){
return (c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y);
} bool cut(node a,node b,node c,node d){
if(cross(a,c,b)*(LL)cross(a,d,b)>=) return ;
if(cross(c,a,d)*(LL)cross(c,b,d)>=) return ;
return ;
} bool check(node a,node b){
for(int i=;i<=n;i++){
if(cut(a,b,L[i].Ld,L[i].Lu)) return ;
if(cut(a,b,L[i].Lu,L[i].Ru)) return ;
if(cut(a,b,L[i].Rd,L[i].Ru)) return ;
if(cut(a,b,L[i].Ld,L[i].Rd)) return ;
}
return ;
} void addedge(node a,node b){
int x=a.id,y=b.id;
long double d=dist(a,b);
E[++totE]=(edge){y,g[x],d}; g[x]=totE;
E[++totE]=(edge){x,g[y],d}; g[y]=totE;
} void buildgraph(node now){
node up=(node){now.x,now.y+},down=(node){now.x,now.y-};
for(int j=;j<=tot;j++){
if(cross(now,P[j],up)<= && cross(now,P[j],down)>=);
if((j&)== && cross(now,P[j],up)<) up=P[j];
if((j&) && cross(now,P[j],down)>) down=P[j];
if((j&)== && P[j].x>=T.x){
if(cross(now,T,up)<= && cross(now,T,down)>=){
printf("%.10lf\n",dist(S,T)/V);
exit();
}
}
}
} void buildgraph2(node now){
node up=(node){now.x,now.y+},down=(node){now.x,now.y-};
for(int j=tot;j>=;j--){
if(cross(now,P[j],up)>= && cross(now,P[j],down)<=)
addedge(now,P[j]);
if((j&)== && cross(now,P[j],up)>) up=P[j];
if((j&) && cross(now,P[j],down)<) down=P[j];
}
} int main(){
// freopen("car2.in","r",stdin);
freopen("noi2011_car.in","r",stdin);
freopen("noi2011_car.out","w",stdout);
scanf("%d",&n);
for(int i=;i<=n;i++) L[i].scan();
S.scan(); S.id=tot+;
T.scan(); T.id=tot+;
if(S.x>T.x) swap(S,T);
scanf("%lf",&V);
for(int i=;i<=tot;i++){
node up=(node){P[i].x,P[i].y+},down=(node){P[i].x,P[i].y-};
for(int j=i+;j<=tot;j++){
if(cross(P[i],P[j],up)<= && cross(P[i],P[j],down)>=)
addedge(P[i],P[j]);
if((j&)== && cross(P[i],P[j],up)<=) up=P[j];
if((j&) && cross(P[i],P[j],down)>=) down=P[j];
}
}
int st=,ed=;
for(int i=;i<=tot;i++){
if(P[i].x==S.x&&P[i].y==S.y) st=i;
if(P[i].x==T.x&&P[i].y==T.y) ed=i;
}
buildgraph(S);
for(int i=;i<=tot+;i++) dis[i]=1e50;
q.push(st); dis[st]=;
while(!q.empty()){
int x=q.front(); q.pop();
v[x]=;
for(int i=g[x];i;i=E[i].to)
if(dis[p]>dis[x]+E[i].v){
dis[p]=dis[x]+E[i].v;
if(!v[p]) q.push(p),v[p]=;
}
}
printf("%.10lf\n",(double)(dis[ed]/V));
return ;
}
T3:阿狸的打字机
树链剖分维护fail树,不错的经典题
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector> #define N 100010
#define MP(x,y) make_pair(x,y)
#define debug(x) cout<<#x<<" = "<<x<<endl;
#define fir first
#define sec second using namespace std; void file(){
freopen("noi2011_type.in","r",stdin);
freopen("noi2011_type.out","w",stdout);
} struct node{
node *ch[],*fail,*fa,*next[];
int v,id;
}*root,*pre[N]; int n,tot,sumv[N],L[N],R[N],g[N],totE,cnt,tott,ansv[N];
char S[N];
vector<pair<int,int> > ask[N]; struct edge{
int x,to;
}E[N<<]; queue<node*> q; void ade(int x,int y){
E[++totE]=(edge){y,g[x]}; g[x]=totE;
} int qsum(int x){
int ans=;
for(;x>;x-=(x&-x)) ans+=sumv[x];
return ans;
} void add(int x,int v){
for(;x<=tot;x+=(x&-x)) sumv[x]+=v;
} void getfail(){
q.push(root);
while(!q.empty()){
node* tmp=q.front(); q.pop();
tmp->id=++tot;
if(tmp!=root) ade(tmp->fail->id,tmp->id);
for(int t=;t<;t++){
if(tmp->ch[t]!=NULL){
if(tmp==root) tmp->ch[t]->fail=root;
else tmp->ch[t]->fail=tmp->fail->ch[t];
q.push(tmp->ch[t]);
}
else{
if(tmp==root) tmp->ch[t]=root;
else tmp->ch[t]=tmp->fail->ch[t];
}
}
}
} #define p E[i].x void dfs(int x){
L[x]=++tott;
for(int i=g[x];i;i=E[i].to) dfs(p);
R[x]=tott;
} void solve(node* x){
add(L[x->id],);
for(int i=ask[x->id].size()-;~i;i--){
int t=ask[x->id][i].fir;
ansv[ask[x->id][i].sec]=qsum(R[t])-qsum(L[t]-);
}
for(int t=;t<;t++)
if(x->next[t]!=NULL) solve(x->next[t]);
add(L[x->id],-);
} int main(){
file();
scanf("%s",S);
root=new node();
node* tmp=root;
for(int i=,len=strlen(S);i<len;i++){
if(S[i]=='P') pre[++cnt]=tmp;
else if(S[i]=='B') tmp=tmp->fa;
else{
int t=S[i]-'a';
if(tmp->ch[t]==NULL){
tmp->ch[t]=new node();
tmp->next[t]=tmp->ch[t];
}
tmp->ch[t]->fa=tmp;
tmp=tmp->ch[t];
}
}
getfail();
dfs(root->id);
scanf("%d",&n);
for(int i=,x,y;i<=n;i++){
scanf("%d%d",&x,&y);
ask[pre[y]->id].push_back(MP(pre[x]->id,i));
}
solve(root);
for(int i=;i<=n;i++)
printf("%d\n",ansv[i]);
fclose(stdin);
fclose(stdout);
return ;
}
Day2
T1:道路修建
233这题。。。。
T2:NOI 嘉年华
读不懂
T3:兔子和蛋蛋
没看
是时候开刷NOI了的更多相关文章
- 开刷LeetCode
还是觉得自己在算法这块太弱鸡了 不多废话开刷吧,LeetCode与算法导论相辅相成双管齐下,期望能填上算法这个坑 解法没意外都是用Python2.7 由于LeetCode有提供Top Solution ...
- NOI 动态规划题集
noi 1996 登山 noi 8780 拦截导弹 noi 4977 怪盗基德的滑翔翼 noi 6045 开餐馆 noi 2718 移动路线 noi 2728 摘花生 noi 2985 数字组合 no ...
- 今天想把iphone4刷成ios7.3beta,折腾半天,成功
今天想把iphone4刷成ios7.3beta,折腾半天,成功 总结如下 1 确认你是无锁机,要是有锁的,就先算了吧.我手里的是台版的无锁,这关过了. 2 得是干净非越狱的,一开始是4.2.1版本的越 ...
- leetcode算法刷题(四)——动态规划(二)
又到了晚上,动态规划,开刷! 第121题 Best Time to Buy and Sell Stock 题目的意思:给予一个数组price,表示特定股票在某天的股价,里面第i个数表示第i天的价格.只 ...
- 用python帮朋友刷帖
0x0前言: 答应了一个朋友帮他刷贴,自己用python写了一个脚本刷. 虽然行为不好..但是缺钱用... 0x01准备: splinter模块: chrome浏览器驱动 0x02开始: 1.进入百度 ...
- Python 自动刷博客浏览量
哈哈,今天的话题有点那什么了哈.咱们应该秉承学习技术的角度来看,那么就开始今天的话题吧. 思路来源 今天很偶然的一个机会,听到别人在谈论现在的"刷量"行为,于是就激发了我的好奇心. ...
- Hasse神舟笔记本卡logo解决,刷BIOS方法,教你修复神船
我的电脑是神舟战神K660E i7 d7的,前两天装Windows10,Ubuntu,MAC OS Mojave,PE 一堆操作,使用bootice重建uefi引导,结果在前几天,我删了一个重复的ue ...
- sony Z5P 刷rec、root的方法
想root需要刷第三方recovery,刷recovery需要先解锁.但如果直接解锁,会丧失相机算法.屏幕超逼真模式,所以不能直接来. 大体步骤就是解完锁后自己做个内核刷进去,欺骗系统让他觉得没解锁. ...
- K2路由器刷机教程
http://blog.sina.com.cn/s/blog_dc642faa0102x1on.html 方法:先降价——刷入breed——刷入固件 1.K2路由固件版本为V22.4.5.39 / V ...
随机推荐
- Info.plist 的字段解释
bundle字段 这些字段名都是XML中的名称,在xcode的属性编辑器中,名字并不相同 bundle目录中的属性列表详细描述了有关该bundle的信息.Finder和一些系统API在一些情况下会使用 ...
- windows10 開機失敗,且按F8無法進入安全模式
windows10 開機失敗,且按F8無法進入安全模式: 在cmd視窗下: bcdedit set {default} bootmenupolicy legacy 重啟,再按F8試一試吧! To En ...
- linux nc,nmap,telnet ,natstat命令
说明 在服务器运维中 通常需要知道 机器端口状态 是否开启 是否被防火墙拦截等.今天我们介绍这三个命令 用来检测端口. nc 命令 / TCP # 安装 yum install -y nc nc 命令 ...
- Effective C++ 条款六 若不想使用编译器自动生成的函数,就该明确拒绝
class HomeForSale //防止别人拷贝方法一:将相应的成员函数声明为private并且不予实现 { public: private: HomeForSale(const HomeForS ...
- 查询历史使用过的命令并使用(history)
一.什么是history 在bash功能中.它能记忆使用过的命令,这个功能最大的优点就是能够查询以前做过的举动.从而能够知道你的执行步骤.那么就能够追踪你曾下达过的命令.以作为除错的工具. 二.His ...
- feed流,图片在左还是右的区别是
feed流设计:那些谋杀你时间APP | 人人都是产品经理 http://www.woshipm.com/pd/773523.html
- Designing a RESTful API with Python and Flask 201
rest服务器的搭建 - CSDN博客 http://blog.csdn.net/zhanghaotian2011/article/details/8760794 REST的架构设计 REST(Rep ...
- Java,多个线程对同一个数据源的访问
当多个线程对同一个数据源进行访问时,应对线程同步或加锁.为何?举个简单的例子:有一个共享的数据源dataSource,其值为0.有两个线程,Thread1和Thread2.Thread1的任务是将da ...
- js中字符串函数indexOf与search的区别
IndexOf()方法是用来判断一个字符串是否存在于一个更长的字符串中.从长字符串左端到右端来搜索,如果存在该子字符串就返回它所处的位置(即索引).如果在被搜索的字符串没有找到要查找的字符串返回-1. ...
- Struts%$#区别
1.#符号的用途一般有三种.1)访问非根对象属性,例如示例中的#session.msg表达式,由于Struts 2中值栈被视为根对象,所以访问其他非根对象时,需要加#前缀.实际上,#相当于Action ...