テストは比較的良好だったが、ないの規格。
しかし、これだけチャネルT1オリジナルタイトルを覚えています。けれども私が行う方法を忘れてしまった、とのデータ範囲は同じではありません。。。ほとんど最初から私は思います。
しかし、精神遅滞のように、運の80ポイントがある完全に間違って書かれた2つの詳細があるので何のACは、存在しないこともいいです。
実際には、二つ以上の詳細を切りました。。。それは元のタイトルがそうフィニッシュまで20分で書き上げ、その後しばらく鍋の後だと思いました。。。
そして、ほとんどおそらく$ O(NK ^ 2)$を感じ、T2を見て?グレート定数。。。しかし、他のではありません。私は非常に良い非常に良いではなくを書きたいです。
これまで暴力のCBXの強い非難した後の水問題の品質は、顔のない行為の試験溶液を補正しないではありません
だから私は半時間を書き込むために、書き込みを始めました。
ルックT3、ああああそのほかのskyhを行うだろう、絶対にすばらしい神(%%%グレート神はテーブルを打ちます)。暴力の混乱を取得するための60分は、(何?誘導??)サンプル上で結論を許可しません。
それは時間半かかりました。別の時間。直接正解T3を与えるために、T2ボードはとても正直ビートに書き込む爆発を知っていました。
修理後に暴力クレイジーパン、ポットは、正の解決策を見つけました。修理に時間半後にああACを修復します。
実際には、良い最初のテストをプレイ。また、非常に賢明なビートに。ただ、詳細を求めているT1速度アンケートに注意を払っていないにもさらされています。
希少な状態試験のライン今日。。。検査の一端の疲れ。。。
そして俊:
清清は32から10に、昨日、ダイナミック、および削除ページをブログ。ちなみに私は前にリーグのダイナミクスを見ました。
どのように退廃Iああ!!!
リーグはまた、爆発に値します。(最近ものの本当に疲れと退屈したが、これは正当な理由ではありません)光、非常に低い効率ではありません退廃も最も最近の期間を考えてみて
自己PROD。今、私は資本をリラックスする必要はありません。。。
それのいくつかは、より強い試してみてください。。。
T1は:コインフリップ
問題の意味:Nコインは、長いa_iを$ $反転間隔(CO $ $ A $ M $種)として一つずつアップ直面し、最後尾の残りの特定の場所$ k個の$正を必要とします。ターンQ.最小数
$ N \ 10000、M \ 100 K \ $ 10
0811NOIPアナログテスト17 T3 "空"。データ範囲のわずかな変化。
しかし、その時点で私は今、問題に対する解決策を書き、その後の話をしませんでした。
XORは、間隔の違いを行うことを考えるのは難しいことではありません。したがって、各$ A $が同時にポイントを離れています。最大$ 2kの$位置に動作する必要があります。
$ 2kの$時間$ BFS $はポイント間の時間の最小数に達した後、形状のプレス$ dpの$を作るためにお互いを見つけてください。
診察室には、2つの詳細をハング:
1,要注意差分之后数列实际上用到了$n+1$位所以上限不要只开到$n$。
2,状压$dp$时每次选出的点对不能与当前状态有交集。
其中状压$dp$的部分可以用那种钦定最小点的思路,这样复杂度会低一些。
最终复杂度$O(2knm+4^kn)$
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,k,dt[11111],bp[22][22],sp[11111],p[22],pc,dp[1048577],q[66666],stp[111]; 4 int main(){ 5 scanf("%d%d%d",&n,&k,&m); 6 for(int i=1,x;i<=k;++i)scanf("%d",&x),sp[x]^=1,sp[x+1]^=1; 7 for(int i=1;i<=n+1;++i)if(sp[i])p[pc]=i,pc++; 8 for(int i=1;i<=m;++i)scanf("%d",&stp[i]); 9 for(int i=0,h,t;i<pc;++i){ 10 memset(dt,0x3f,sizeof dt);dt[p[i]]=0;q[h=t=1]=p[i]; 11 for(;h<=t;++h){ 12 for(int j=1;j<=m;++j){ 13 if(q[h]+stp[j]<=n+1&&dt[q[h]+stp[j]]>dt[q[h]]+1)dt[q[++t]=q[h]+stp[j]]=dt[q[h]]+1; 14 if(q[h]-stp[j]>0&&dt[q[h]-stp[j]]>dt[q[h]]+1)dt[q[++t]=q[h]-stp[j]]=dt[q[h]]+1; 15 } 16 }for(int j=0;j<pc;++j)bp[i][j]=dt[p[j]]; 17 } 18 memset(dp,0x3f,sizeof dp);dp[0]=0; 19 for(int s=0;s<(1<<pc)-1;++s){ 20 int fs; 21 for(int j=0;j<pc;++j)if(!(s&1<<j)){fs=j;break;} 22 for(int j=fs+1;j<pc;++j)if(!(s&1<<j))dp[s|1<<fs|1<<j]=min(dp[s|1<<fs|1<<j],dp[s]+bp[j][fs]); 23 } 24 printf("%d\n",dp[(1<<pc)-1]>6666666?-1:dp[(1<<pc)-1]); 25 }
T2:回文子串
题意:给定一个字符串,支持区间改为某一个字符,询问区间长度小于等于$k$的回文串个数。$n,m\le 50000,k\le 50$
突破口自然在$k$。除非你像cbx大神直接n2过。
维护i一个数组$a_{i,j}$表示以$j$结尾的长度为$i$的回文串是否存在$(0/1)$。查询就直接区间$k$次区间和。
如果修改的区间很长,那么对于$[l+k-1,r]$这些位置它们一定都是$1$。区间赋值。
而对于$[l,l+k-1],[r+1,r+k]$这两部分暴力重构,长度很短所以复杂度可以接受。
维护$50$个线段树。对于查询字符串,于是再开个线段树维护字符串。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define lc p<<1 4 #define rc p<<1|1 5 #define md (cl+cr>>1) 6 #define S 222222 7 char rs[S];int k,q,s[S],ss[S],n;unsigned long long h1[S],h2[S],pw[S]; 8 int palin(int l,int r){return h1[r]-h1[l-1]*pw[r-l+1]==h2[l]-h2[r+1]*pw[r-l+1];} 9 void build_str(int p,int cl,int cr){ 10 if(cl==cr){s[p]=rs[cl]-'a'+1;return;} 11 build_str(lc,cl,md); 12 build_str(rc,md+1,cr); 13 } 14 void down_str(int p){if(s[p])s[lc]=s[p],s[rc]=s[p],s[p]=0;} 15 void ask_str(int l,int r,int p=1,int cl=1,int cr=n){ 16 if(cl==cr){ss[cl]=s[p];return;} 17 down_str(p); 18 if(l<=md)ask_str(l,r,lc,cl,md); 19 if(r>md)ask_str(l,r,rc,md+1,cr); 20 } 21 void chg_str(int l,int r,int w,int p=1,int cl=1,int cr=n){ 22 if(l<=cl&&cr<=r){s[p]=w;return;} 23 down_str(p); 24 if(l<=md)chg_str(l,r,w,lc,cl,md); 25 if(r>md)chg_str(l,r,w,rc,md+1,cr); 26 } 27 struct Segment_Tree{ 28 int w[S];bool lz[S]; 29 void chg(int l,int r,int p=1,int cl=1,int cr=n){ 30 if(l<=cl&&cr<=r){w[p]=cr-cl+1;lz[p]=1;return;} 31 if(l<=md)chg(l,r,lc,cl,md); 32 if(r>md)chg(l,r,rc,md+1,cr); 33 w[p]=w[lc]+w[rc]; 34 } 35 void rebuild(int l,int r,int p=1,int cl=1,int cr=n){ 36 if(cl==cr){w[p]=ss[cl];return;} 37 if(lz[p])w[lc]=md-cl+1,w[rc]=cr-md,lz[lc]=lz[rc]=1,lz[p]=0; 38 if(l<=md)rebuild(l,r,lc,cl,md); 39 if(r>md)rebuild(l,r,rc,md+1,cr); 40 w[p]=w[lc]+w[rc]; 41 } 42 int ask(int l,int r,int p=1,int cl=1,int cr=n){ 43 if(r<l)return 0; 44 if(l<=cl&&cr<=r)return w[p]; 45 if(lz[p])w[lc]=md-cl+1,w[rc]=cr-md,lz[lc]=lz[rc]=1,lz[p]=0; 46 return (l<=md?ask(l,r,lc,cl,md):0)+(r>md?ask(l,r,rc,md+1,cr):0); 47 } 48 }T[55]; 49 int main(){//freopen("2.in","r",stdin);freopen("A.out","w",stdout); 50 scanf("%s%d%d",rs+1,&k,&q);n=strlen(rs+1);build_str(1,1,n); 51 pw[0]=1;for(int i=1;i<=k+1;++i)pw[i]=pw[i-1]*29; 52 for(int i=1;i<=n;++i)h1[i]=h1[i-1]*29+rs[i]-'a'+1; 53 for(int i=n;i;--i)h2[i]=h2[i+1]*29+rs[i]-'a'+1; 54 for(int len=2;len<=k;++len){ 55 for(int i=len;i<=n;++i)ss[i]=palin(i-len+1,i); 56 T[len].rebuild(len,n); 57 } 58 while(q-->0){ 59 int opt,l,r,L,R;scanf("%d%d%d",&opt,&l,&r); 60 if(opt==1){ 61 scanf("%s",rs);chg_str(l,r,rs[0]-'a'+1);L=max(1,l+1-k);R=min(n,r+k-1); 62 if(r-l+1<=k){ 63 ask_str(L,R); 64 for(int i=L;i<=R;++i)h1[i]=h1[i-1]*29+ss[i]; 65 for(int i=R;i>=L;--i)h2[i]=h2[i+1]*29+ss[i]; 66 for(int len=2;len<=k;++len){ 67 for(int i=l;i<=R;++i)ss[i]=i>=len?palin(i-len+1,i):0; 68 T[len].rebuild(l,R); 69 } 70 }else{ 71 ask_str(L,l+k-1); 72 for(int i=L;i<=l+k-1;++i)h1[i]=h1[i-1]*29+ss[i]; 73 for(int i=l+k-1;i>=L;--i)h2[i]=h2[i+1]*29+ss[i]; 74 for(int len=2;len<=k;++len){ 75 for(int i=l;i<=l+len-2;++i)ss[i]=palin(i-len+1,i); 76 T[len].rebuild(l,l+len-2); 77 } 78 ask_str(r-k+1,R); 79 for(int i=r-k+1;i<=R;++i)h1[i]=h1[i-1]*29+ss[i]; 80 for(int i=R;i>=r-k+1;--i)h2[i]=h2[i+1]*29+ss[i]; 81 for(int len=2;len<=k;++len){ 82 for(int i=r+1;i<=r+len-1&&i<=n;++i)ss[i]=palin(i-len+1,i); 83 T[len].rebuild(r+1,min(n,r+len-1)); 84 } 85 for(int len=2;len<=k;++len)T[len].chg(l+len-1,r); 86 } 87 }else{ 88 int ans=r-l+1; 89 for(int i=2;i<=k&&i<=r-l+1;++i)ans+=T[i].ask(l+i-1,r); 90 printf("%d\n",ans); 91 } 92 } 93 }
T3:最大权值
题意:$n$物品有参数$a,b$,选出$k$件任意排列的价值为$\sum b+a\times (p-1)$。求对所有$1\le k \le n$的最大价值。
$n \le 300000, a \le 10^6,b \le 10^{12}$
大神都用$\% d$读$b$。
显然(?)选$k$个物品时的集合是$k+1$时的子集,其实只是插入一个元素其余相对位置不变。
设$dp_{i,j}$表示考虑前$i$个物品选出$j$个的最大收益,做个差分就是每个元素的贡献,设为$g$。
打表发现$dp$转移时两种转移之间有一个明确的分界。考虑二分。
每个点的贡献就是按照题意那么维护,插入一个点之后它左端的点权值不变,右端的要增加一个$a_i$。
插入,区间加,二分。$splay$
不难写。不好想。
$splay$上二分以及$dp$打表都是挺好的思路,记一下。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 333333 4 struct ps{ 5 long long a,b; 6 friend bool operator<(ps x,ps y){return x.a<y.a;} 7 }P[S]; 8 int n,c[2][S],f[S],sz[S],s[S],rt,I,C;long long lz[S],w[S],g[S]; 9 void down(int p){ 10 if(!lz[p])return; 11 w[c[0][p]]+=lz[p];lz[c[0][p]]+=lz[p]; 12 w[c[1][p]]+=lz[p];lz[c[1][p]]+=lz[p]; 13 lz[p]=0; 14 } 15 void up(int p){sz[p]=sz[c[0][p]]+sz[c[1][p]]+1;} 16 void spin(int p){ 17 int F=f[p],G=f[F],d=c[1][F]==p,B=c[!d][p]; 18 if(G)c[c[1][G]==F][G]=p; c[d][c[!d][p]=F]=B; 19 if(B)f[B]=F; f[f[F]=p]=G; 20 up(p);up(F); 21 } 22 void splay(int p){ 23 int F=p,tp=0;while(F)s[++tp]=F,F=f[F];while(tp)down(s[tp]),tp--; 24 for(;F=f[p];spin(p))if(f[F])spin(c[1][f[F]]==F^c[1][F]==p?p:F);rt=p; 25 } 26 void find(int p){ 27 int lp,tsz=0,d; 28 while(p){ 29 down(p); 30 if(w[p]>P[I].a*(tsz+sz[c[0][p]])+P[I].b)tsz+=sz[c[0][p]]+1,p=c[d=1][lp=p]; 31 else p=c[d=0][lp=p]; 32 } 33 f[I]=lp;c[d][lp]=I;w[I]=P[I].a*tsz+P[I].b;sz[I]=1; 34 splay(I);lz[c[1][I]]+=P[I].a;w[c[1][I]]+=P[I].a; 35 } 36 void dfs(int p){ 37 if(!p)return; 38 down(p); 39 dfs(c[0][p]); 40 g[++C]=w[p]; 41 dfs(c[1][p]); 42 } 43 int main(){//freopen("1.in","r",stdin); 44 scanf("%d",&n); 45 for(int i=1;i<=n;++i)scanf("%lld%lld",&P[i].a,&P[i].b); 46 sort(P+1,P+1+n); 47 rt=1;w[1]=P[1].b;sz[1]=1; 48 for(I=2;I<=n;++I)find(rt); 49 dfs(rt); 50 for(int i=1;i<=n;++i)g[i]+=g[i-1],printf("%lld\n",g[i]); 51 }