[考試反思]1107csp-s模擬測試104: 速度

20分鐘能作什麼?c++

不粘排行榜,沒意義,第一機房集體重啓,我僥倖找回了兩個文件纔有分。ide

實際得分應該是70+100+60,第二機房rank1。。。放在第一機房就不知道了優化

 

T1:中間值ui

比較喜歡題解的第二種作法。spa

考慮分治。如今要求出a[l,r],b[L,R]以內的第k小值。指針

遞歸邊界:若是k==1,那麼就是min(a[l],b[L])。若是一個區間爲空,直接返回另外一個區間的第k小值。code

不然咱們在a和b中分別取出一些元素,與k的一半取min,而後比較這個元素blog

即設t=min(k>>1,r-l+1).排序

那麼咱們能夠比較a[l+t]與b[L+k-t]。較小的一邊就能夠排除了,繼續遞歸解決便可。遞歸

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 int n,m,a[500005],b[500005];
 5 int read(){
 6     register int p=0,nt=0;register char ch=getchar();
 7     for(;ch<'0'||ch>'9';ch=getchar())nt=ch=='-';
 8     for(;ch>='0'&&ch<='9';p=(p<<3)+(p<<1)+ch-48,ch=getchar());
 9     return nt?-p:p;
10 }
11 int chk(int l,int r,int L,int R,int k){//printf("%d %d %d %d %d\n",l,r,L,R,k);
12     if(k==1)return min(a[l],b[L]);
13     if(l>r)return b[L+k-1];
14     if(L>R)return a[l+k-1];
15     int t=min(min(r-l+1,R-L+1),k>>1);
16     if(a[l+t-1]>b[L+t-1])return chk(l,r,L+t,R,k-t);
17     else return chk(l+t,r,L,R,k-t);
18 }
19 int main(){
20     freopen("median.in","r",stdin);freopen("median.out","w",stdout);
21     scanf("%d%d",&n,&m);
22     for(int i=1;i<=n;++i)a[i]=read();
23     for(int i=1;i<=n;++i)b[i]=read();
24     while(m--){
25         int opt;scanf("%d",&opt);
26         if(opt==1){
27             int x=read(),y=read(),z=read();
28             if(!x)a[y]=z;else b[y]=z;
29         }else{
30             int l=read(),r=read(),L=read(),R=read(),cnt;
31             printf("%d\n",chk(l,r,L,R,R-L+r-l+3>>1));
32         }
33     }
34 }
View Code

 

T2:最小值

感受像單調棧,可是單調棧裏的值均可能是最優決策。

發現轉移值與當前點位置無關,因此直接把轉移值放進set。彈棧時刪除。

 1 #include<cstdio>
 2 #include<set>
 3 using namespace std;
 4 #define inf -12345678901234567
 5 multiset<long long>S;
 6 long long A,B,C,D,dp[200005],val[200005];int n,x[200005],s[200005],tp;
 7 long long cal(int x){return A*x*x*x+B*x*x+C*x+D;}
 8 struct Segment_Tree{
 9     long long w[800005];
10     void modify(int p,int pos,long long v,int cl=0,int cr=n){
11         if(cl==cr){w[p]=v;return;}
12         if(pos<=cl+cr>>1)modify(p<<1,pos,v,cl,cl+cr>>1);
13         else modify(p<<1|1,pos,v,(cl+cr>>1)+1,cr);
14         w[p]=max(w[p<<1],w[p<<1|1]);
15     }
16     long long ask(int p,int l,int r,int cl=0,int cr=n){
17         if(l<=cl&&cr<=r)return w[p];
18         return max(l<=cl+cr>>1?ask(p<<1,l,r,cl,cl+cr>>1):inf,r>cl+cr>>1?ask(p<<1|1,l,r,(cl+cr>>1)+1,cr):inf);
19     }
20 }T;
21 int main(){
22     freopen("min.in","r",stdin);freopen("min.out","w",stdout);
23     scanf("%d%lld%lld%lld%lld",&n,&A,&B,&C,&D);
24     for(int i=1;i<=n;++i)scanf("%d",&x[i]);
25     for(int i=1;i<=n;++i){
26         while(tp&&x[s[tp]]>x[i])S.erase(S.find(val[tp])),tp--;
27         s[++tp]=i;val[tp]=T.ask(1,s[tp-1],i-1)+cal(x[i]);S.insert(val[tp]);
28         dp[i]=*(--S.end());T.modify(1,i,dp[i]);
29     }printf("%lld\n",dp[n]);
30 }
View Code

 

T3:最大值

寫的不是題解思路,稍麻煩,碼量較大,思惟量較大,較麻煩,常數也稍大(須要zkw+fread+取模優化而且還不能亂開long long才能卡過。。。)

能夠發現,由於不包含,因此詢問按左端點排序以後,右端點也就單調了。

因此其實能夠兩個單調指針掃一遍,操做就相似於莫隊了。

每一個魔法陣內部的各類取值的機率比較好計算,從小到大依次考慮,每一個元素的機率就是前面全部項$1-p$的乘積再乘這個取值的p。

對於剩下的機率,還要加入一個0。

關鍵在於魔法陣之間的影響。

暴力的思路就是把區間內的魔法陣都加入set,而後按照和上面同樣的方法依次考慮。

只不過要注意,對於任意一個可能值,它的機率都不會受到他本身來源的魔法陣的影響,須要除去。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define int long long
 4 #define mod 1000000007
 5 #define ip(p) (1000000008-p)
 6 int qpow(int b,int t,int a=1){for(;t;t>>=1,b=b*b%mod)if(t&1)a=a*b%mod;return a;}
 7 #define inv(p) qpow(p,mod-2)
 8 struct P{
 9     int w,p,b;
10     friend bool operator<(P a,P b){return a.w<b.w;}
11 }p;
12 struct Q{
13     int l,r;
14     friend bool operator<(Q a,Q b){return a.l<b.l;}
15 }qs[200005];
16 vector<P>v[200005],V[200005];
17 multiset<P>S;
18 int n,m,q,alpos[200005],ans;
19 main(){freopen("max.in","r",stdin);freopen("max.out","w",stdout);
20     scanf("%lld%lld%lld",&n,&m,&q);
21     for(int i=1;i<=m;++i)scanf("%lld%lld%lld",&p.b,&p.w,&p.p),v[p.b].push_back(p);
22     for(int i=1;i<=n;++i){
23         sort(v[i].begin(),v[i].end());
24         int rpos=1;
25         for(int j=0;j<v[i].size();++j)V[i].push_back((P){v[i][j].w,v[i][j].p*rpos%mod,i}),rpos=rpos*ip(v[i][j].p)%mod;
26         V[i].push_back((P){0,rpos,i});
27     }
28     for(int i=1;i<=q;++i)scanf("%lld%lld",&qs[i].l,&qs[i].r);
29     sort(qs+1,qs+1+q);qs[0].l=1;
30     for(int i=1;i<=q;++i){
31         for(int j=qs[i-1].r+1;j<=qs[i].r;++j)for(int k=0;k<V[j].size();++k)S.insert(V[j][k]);
32         for(int j=qs[i-1].l;j<qs[i].l;++j)for(int k=0;k<V[j].size();++k)S.erase(S.find(V[j][k]));
33         int rpos=1;
34         for(int j=qs[i].l;j<=qs[i].r;++j)alpos[j]=1;
35         for(set<P>::reverse_iterator it=S.rbegin();it!=S.rend();++it){P It=*it;
36             rpos=(rpos*inv(alpos[It.b]))%mod;
37             ans=(ans+rpos*It.p%mod*It.w)%mod;
38             alpos[It.b]=(mod+alpos[It.b]-It.p)%mod;
39             rpos=rpos*alpos[It.b]%mod;
40         }
41     }printf("%lld\n",ans);
42 }
60分暴力

考慮線段樹維護。離散化,下標爲水晶的能量。

爲了方便處理(而且保證答案正確),咱們要強制全部能量值相等的水晶有固定的前後次序,加一個沒有意義的第二關鍵字來進行排序。

(不然的話,對於一個同一個能量值的水晶,它們互相影響就會致使答案值偏小)

就是不存在A限制了B的同時B也限制了A的狀況(本身舉個權值相同的例子就好)

而後你依次考慮每個水晶,它會產生的影響是:來自其它魔法陣的能量值更小及相等的晶石產生貢獻的機率要乘上1-p。而後固然要把本身的出現機率累加。

線段樹維護區間乘,單點加。並無區間查詢,由於你每次查詢都是查的整棵樹,及時uodate,最後直接拿1號點的權值就行了。

注意這裏的區間乘法是要持續生效的,不僅做用於當前值,也就是之後再加入某一個值的時候,還要再乘上之前的乘法標記。

因此採用了標記永久化。

要注意一些地方:一個晶石並不會對來自與同一魔法陣的晶石產生影響,可是乘法標記是區間一塊兒打上的不能區分,因此在進行區間加的時候,還要除以之前來自同一魔法陣所打上的乘法標記。

同時還要再考慮,你區間乘好像是每次都從1到某一個位置,那麼來自同一個魔法陣的晶石可能對低位產生了屢次影響。

因此在下一個晶石乘的時候,還要把它控制的區間內它以前的一顆晶石產生的影響刪除(就是乘逆元)

而後還要考慮從線段樹裏刪除魔法陣。

單點加變減。區間乘變乘逆元。

看起來沒有什麼問題。可是當你發現須要乘0的時候世界就崩塌了。

區間乘0其實還好說,關鍵是之後在刪除魔法陣時還要消除這個乘0的影響。

乘0的逆元?不存在啊。

因此線段樹上還要特殊處理一下乘0的標記。每次乘的時候標記+1,每次乘「0的逆元」時標記-1。

只要有標記存在,就證實這段區間的機率都是0,因此對答案的貢獻也就是0。

在代碼裏我就把「0的逆元」設定爲-1了。

而後就是卡常。。。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define ll long long
  4 #define mod 1000000007
  5 int Mod(ll x){return x>=mod?x-mod:x;}
  6 const int L=1<<20|1;
  7 char buffer[L],*S,*Q;
  8 #define getchar() ((S==Q&&(Q=(S=buffer)+fread(buffer,1,L,stdin),S==Q))?EOF:*S++)
  9 const int maxn=100000+5;
 10 int read(){
 11     register int p=0;register char ch=getchar();
 12     while(ch<'0'||ch>'9')ch=getchar();
 13     while(ch>='0'&&ch<='9')p=(p<<3)+(p<<1)+ch-48,ch=getchar();
 14     return p;
 15 }
 16 ll qpow(ll b,int t,ll a=1){for(;t;t>>=1,b=b*b%mod)if(t&1)a=a*b%mod;return a;}
 17 struct P{
 18     ll w,p;int b,rk;
 19     friend bool operator<(P a,P b){return a.w<b.w;}
 20 }p;
 21 struct N{
 22     ll w;int ord;
 23     friend bool operator<(N a,N b){return a.w<b.w||(a.w==b.w&&a.ord<b.ord);}
 24 }W[300005];
 25 ll inv(ll p){return p?qpow(p,mod-2):-1;}
 26 ll ip(ll p){return (mod+1-p)%mod;}
 27 vector<P>v[200005],V[200005];
 28 int n,m,q,K,k,l[100005],r[100005];ll ans;
 29 struct Segment_Tree{
 30     ll w[1200005],lz[1200008];int NONE[1200008];
 31     int cal(int p){return NONE[p]?0:lz[p]*w[p]%mod;}
 32     int bit;
 33     void build(){
 34         for(bit=1;bit<=k+1;bit<<=1);
 35         for(int i=1;i<=bit+bit;++i) lz[i]=1; 
 36     }
 37     void mult(int l,int r,ll v){
 38         for(l+=bit-1,r+=bit+1;l^r^1;){
 39             if(~l&1){
 40                 if(v>0) lz[l^1]=lz[l^1]*v%mod;
 41                 else if(!v)NONE[l^1]++;
 42                 else NONE[l^1]--;
 43             }
 44             if(r&1){
 45                 if(v>0) lz[r^1]=lz[r^1]*v%mod;
 46                 else if(!v)NONE[r^1]++;
 47                 else NONE[r^1]--;
 48             }
 49             l>>=1; r>>=1;
 50             w[l]=Mod(cal(l<<1)+cal(l<<1|1));
 51             w[r]=Mod(cal(r<<1)+cal(r<<1|1));
 52         }
 53         for(l>>=1;l;l>>=1) w[l]=Mod(cal(l<<1)+cal(l<<1|1));
 54     }
 55     void add(int p,ll v){
 56         p+=bit; w[p]=(w[p]+v*W[p-bit].w)%mod;
 57         for(p>>=1;p;p>>=1) w[p]=Mod(cal(p<<1)+cal(p<<1|1));
 58     }
 59 }T;
 60 bool com(P a,P b){return a.w>b.w;}
 61 main(){
 62     freopen("max.in","r",stdin);
 63     freopen("max.out","w",stdout);
 64     scanf("%d%d%d",&n,&m,&q);
 65     for(int i=1;i<=m;++i)p.b=read(),p.w=read(),p.p=read(),v[p.b].push_back(p);
 66     for(int i=1;i<=n;++i){
 67         sort(v[i].begin(),v[i].end());
 68         ll rpos=1;
 69         for(int j=0;j<v[i].size();++j)V[i].push_back((P){v[i][j].w,v[i][j].p*rpos%mod,i,++K}),rpos=rpos*ip(v[i][j].p)%mod;
 70         V[i].push_back((P){0,rpos,i,++K});
 71     }
 72     for(int i=1;i<=n;++i)for(int j=0;j<V[i].size();++j)W[++k]=(N){V[i][j].w,V[i][j].rk};
 73     sort(W+1,W+1+k);T.build();
 74     for(int i=1;i<=n;++i)for(int j=0;j<V[i].size();++j)V[i][j].w=lower_bound(W+1,W+1+k,(N){V[i][j].w,V[i][j].rk})-W;
 75     for(int i=1;i<=n;++i)sort(V[i].begin(),V[i].end(),com);
 76     for(int i=1;i<=q;++i)l[i]=read(),r[i]=read();
 77     l[0]=1;
 78     for(int i=1;i<=q;++i){
 79         for(int j=r[i-1]+1;j<=r[i];++j){
 80             ll totpos=0;
 81             for(int k=0;k<V[j].size();++k){
 82                 if(V[j][k].p==0)continue;
 83                 ll TP=totpos;totpos=Mod(totpos+V[j][k].p);
 84                 T.mult(1,V[j][k].w-1,ip(totpos));
 85                 if(k)T.mult(1,V[j][k].w,inv(ip(TP)));
 86                 T.add(V[j][k].w,V[j][k].p);
 87             }
 88         }
 89         for(int j=l[i-1];j<l[i];++j){
 90             ll totpos=0;
 91             for(int k=0;k<V[j].size();++k){
 92                 if(V[j][k].p==0)continue;
 93                 totpos=Mod(totpos+V[j][k].p);
 94                 T.mult(1,V[j][k].w-1,inv(ip(totpos)));
 95                 if(k)T.mult(1,V[j][k].w-1,ip(totpos-V[j][k].p));
 96                 T.add(V[j][k].w,mod-V[j][k].p);
 97             }
 98         }
 99         ans=(ans+T.w[1]*T.lz[1])%mod;
100     }printf("%lld\n",ans);
101 }
View Code

由於細節實在太多,因此哪一個地方不會的話在評論區裏問,一個一個細節來說確定是說不完的。。。

相關文章
相關標籤/搜索