暴力沒打滿。。。有點垃圾。。。
考得稍絕望,啥也不會啊???
T3的測試點分治還寫掛了。。。
其實就是沒有沉下心好好的思考,在三道題上來回切換結果一個成型思路都沒有
T2既然已經想到那一步了居然沒有繼續想下去。。。
不管怎么說,還是思路凌亂了,沒有穩下來
但是,也算是混進第一雞房了,也是新的自我調整的機會吧
沒怎么頹廢,改題也快了。。。感覺不錯
這是一個好的桌面背景。(Ubuntu Mono Bold Italic 150號字)
T1:trade
剛開始以為要怎么優化dp。但是這其實是一個比較明顯的反悔型貪心。
因為取消賣出和進行買入這兩個操作本質是一樣的,往堆里扔就是了。
買a賣b再買b賣c,和買a賣c是等價的,這樣就做到了反悔。
當你決定賣的時候就往堆里扔一個用於反悔賣出這個決定。
然后每個元素都還要往堆里扔一個來用於正常的買入。
代碼比暴力dp還好寫。

1 #include<cstdio> 2 #include<queue> 3 using namespace std; 4 priority_queue<int,vector<int>,greater<int> >q; 5 int n,x;long long ans; 6 main(){ 7 scanf("%d%d",&n,&x);q.push(x);n--; 8 while(n--){ 9 scanf("%d",&x); 10 if(x>q.top())ans+=x-q.top(),q.pop(),q.push(x); 11 q.push(x); 12 }printf("%lld\n",ans); 13 }
思路積累:
- 反悔型貪心:正確性證明與數據結構結合達到最優決策
T2:sum
根據定義,有S[i][j]=S[i][j-1]+C[i][j]
打表發現,有S[i][j]=S[i-1][j-1]+S[i-1][j]
用含義就可以知道:i個里至多選j個,隨意指定其中一個元素,如果它選,那么就在剩下的i-1里至多選j-1個,如果它不選,那就在剩下的i-1里選至多j個
合並一下,有S[i][j]=S[i-1][j]*2-C[i-1][j]
這樣的形式就可以做到O(1)的把數組的某一維變化1了。可以莫隊了。

1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 #define int long long 5 #define mod 1000000007 6 struct qs{int m,n,id;friend bool operator<(qs a,qs b){return a.n/400!=b.n/400?a.n/400<b.n/400:a.m/400<b.m/400;}}q[100005]; 7 int fac[100005],inv[100005],invv[100005],id,Q,n,m,ans[100005]; 8 int C(int b,int t){return b<t?0:fac[b]*inv[t]%mod*inv[b-t]%mod;} 9 main(){//freopen("sum1.in","r",stdin);freopen("my.out","w",stdout); 10 fac[0]=invv[1]=inv[1]=inv[0]=fac[1]=1; 11 for(int i=2;i<=100000;++i)fac[i]=fac[i-1]*i%mod,invv[i]=mod-mod/i*invv[mod%i]%mod,inv[i]=inv[i-1]*invv[i]%mod; 12 scanf("%lld%lld",&id,&Q); 13 int x=1,y=1,Ans=2; 14 for(int i=1;i<=Q;++i)scanf("%lld%lld",&q[i].n,&q[i].m),q[i].id=i; 15 sort(q+1,q+1+Q); 16 for(int i=1;i<=Q;++i){ 17 while(x<q[i].n)Ans=(Ans+Ans-C(x,y)+mod)%mod,++x; 18 while(x>q[i].n)--x,Ans=(Ans+C(x,y))*500000004ll%mod; 19 while(y<q[i].m)++y,Ans=(Ans+C(x,y))%mod; 20 while(y>q[i].m)Ans=(Ans-C(x,y)+mod)%mod,--y; 21 ans[q[i].id]=Ans; 22 }for(int i=1;i<=Q;++i)printf("%lld\n",ans[i]); 23 }
思路積累:
- 莫隊和分塊思路在遞推表達式求值上的應用
但是還是想講一下自己傻逼的部分分想法:m全部相同的20分。
$S_{n,m}=\sum\limits_{i=0}^m C_{n,i} $
$=\sum\limits_{i=0}^m n! \times inv(i!) \times inv((n-i)!)$
$= n! \sum\limits_{i=0}^m inv(i!) \times inv((n-i)!) $
然后后面就是一個比較明顯的卷積形式了。
因為求和只是到m為止,所以不能直接把兩個inv套起來,對於第一個inv數組大於m的項賦成0就可以解決這個問題了。
然后我們就能求出對於每一個n后面的那個卷積式了,就可以O(1)回答詢問了。
因為模數是1000000007,不是一個好的NTT模數,所以需要多模數CRT一發。
思路還好,就是如果考場上我要是打這個的話可能就不用干別的了。
又是用省選知識點打聯賽暴力的好例子
誠當是磨礪思維吧(雖然在考場上耽誤了不少時間)
T3:building
loj差點就讓我棄坑了。
對於詢問有多少個塊,這還是比較好做的,差分一下O(1)修改,最后求兩遍前綴和。
至於聯通塊,容易想起以前的結論:在無環圖上,聯通塊數=點數-邊數
然而這道題有環。我們把每一次操作作為一個點,把相鄰的操作建邊,求聯通塊。
可以利用並查集,這樣它就成了樹型的了,就可以用點數-邊數了。
建邊的時候,如果發現它們已經聯通,那么就不再建邊,這樣就保證了無環。
我的思路是橫邊只與橫邊相鄰,豎邊只與豎邊有相鄰。
那么怎么考慮橫邊與豎邊之間的相鄰呢?
可以發現如果橫邊與豎邊相鄰的話,其實就是其中的一條邊與另一條邊的某一個端點相鄰。
這樣的話,我們在加入某一條橫邊的時候,同時也把它的兩個端點當成豎邊加入。加入豎邊時同理。
然后逐行掃,不斷加入x1小的邊即可。
暴力的做法是爆掃相鄰的兩行/列枚舉每一個塊。這樣的復雜度在極端時會被卡成n2。
但是本題沒有卡可以AC,雖說跑的很慢而且我的方法有有3倍量的塊。2900ms。

1 #include<cstdio> 2 #include<vector> 3 #include<algorithm> 4 #include<iostream> 5 using namespace std; 6 struct ps{int x1,x2,y1,y2,ord;friend bool operator<(ps a,ps b){return a.x1<b.x1;}}p[100005]; 7 vector<ps>L[100005],R[100005]; 8 int ans,cf[100005],f[100005],cb[100005],eds; 9 int find(int k){return f[k]==k?k:f[k]=find(f[k]);} 10 void link(int a,int b){ 11 int fa=find(a),fb=find(b); 12 if(fa!=fb)eds++,f[fa]=fb; 13 } 14 int main(){ 15 int id,n,m,k,q,qk,qx,pt=1;scanf("%d%d%d%d%d",&id,&n,&m,&k,&q); 16 for(int i=1,x1,x2,y1,y2;i<=k;++i){ 17 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 18 p[i]=(ps){x1,x2,y1,y2,f[i]=i}; 19 if(x1==x2)cf[x1]+=y2-y1+1,cf[x1+1]-=y2-y1+1; 20 else cf[x1]++,cf[x2+1]--; 21 } 22 for(int i=1;i<=n;++i)cf[i]+=cf[i-1]; 23 for(int i=1;i<=n;++i)cf[i]+=cf[i-1]; 24 sort(p+1,p+k+1); 25 for(int I=1;I<=n;cb[I]=pt-eds-1,++I)while(p[pt].x1==I&&pt<=k){ 26 int x1=p[pt].x1,x2=p[pt].x2,y1=p[pt].y1,y2=p[pt].y2,ord=p[pt].ord,X1=x1-1,X2=x2+1,Y1=y1-1,Y2=y2+1; 27 for(int i=0;i<L[X1].size();++i)if(!(L[X1][i].y1>y2||L[X1][i].y2<y1))link(L[X1][i].ord,ord); 28 for(int i=0;i<R[Y1].size();++i)if(!(R[Y1][i].x1>x2||R[Y1][i].x2<x1))link(R[Y1][i].ord,ord); 29 for(int i=0;i<L[X2].size();++i)if(!(L[X2][i].y1>y2||L[X2][i].y2<y1))link(L[X2][i].ord,ord); 30 for(int i=0;i<R[Y2].size();++i)if(!(R[Y2][i].x1>x2||R[Y2][i].x2<x1))link(R[Y2][i].ord,ord); 31 ps P1=(ps){x1,x1,y1,y1,ord},P2=(ps){x2,x2,y2,y2,ord}; 32 if(y1==y2)R[y1].push_back(p[pt]),L[x2].push_back(P2),L[x1].push_back(P1); 33 else L[x1].push_back(p[pt]),R[y2].push_back(P2),R[y1].push_back(P1); 34 pt++; 35 } 36 while(q--)scanf("%d%d",&qk,&qx),printf("%d\n",qk?cb[qx]:cf[qx]); 37 }
肯定是可以優化的。一種是把vector改成set這樣的話常數會非常大最后可能比暴力還慢。
另一種就是先把所有邊都加入然后sort,用lower_bound查詢並及時break就行。
要注意你建邊時只與前面行的建邊,沒有掃到的行不要建。
QAQnlog的代碼還沒有寫等會馬上跟上啊我沒臉溜了
QAQ打完超級長的nlog的正解了但是它跑的比暴力還慢啊啊啊常數這么丑2940ms但是好歹打正解了我又有臉了啊啊啊溜了

1 #include<cstdio> 2 #include<vector> 3 #include<algorithm> 4 #include<iostream> 5 using namespace std; 6 struct ps{int x1,x2,y1,y2,ord;friend bool operator<(ps a,ps b){return a.x1!=b.x1?a.x1<b.x1:a.y1<b.y1;}}p[100005]; 7 vector<ps>L[100005],R[100005]; 8 int ans,cf[100005],f[100005],cb[100005],eds; 9 int find(int k){return f[k]==k?k:f[k]=find(f[k]);} 10 void link(int a,int b){ 11 int fa=find(a),fb=find(b);//printf("link:%d %d\n",a,b); 12 if(fa!=fb)eds++,f[fa]=fb; 13 } 14 int main(){//freopen("building1.in","r",stdin); 15 int id,n,m,k,q,qk,qx,pt=1;scanf("%d%d%d%d%d",&id,&n,&m,&k,&q); 16 for(int i=1,x1,x2,y1,y2;i<=k;++i){ 17 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 18 p[i]=(ps){x1,x2,y1,y2,f[i]=i}; 19 ps P1=(ps){x1,x1,y1,y1,i},P2=(ps){x2,x2,y2,y2,i}; 20 if(x1==x2)cf[x1]+=y2-y1+1,cf[x1+1]-=y2-y1+1,L[x1].push_back(p[i]),R[y2].push_back(P2),R[y1].push_back(P1); 21 else cf[x1]++,cf[x2+1]--,R[y1].push_back(p[i]),L[x2].push_back(P2),L[x1].push_back(P1); 22 } 23 for(int i=1;i<=n;++i)cf[i]+=cf[i-1]; 24 for(int i=1;i<=n;++i)cf[i]+=cf[i-1]; 25 for(int i=1;i<=n;++i)sort(L[i].begin(),L[i].end()); 26 for(int i=1;i<=m;++i)sort(R[i].begin(),R[i].end()); 27 sort(p+1,p+k+1); 28 for(int I=1;I<=n;cb[I]=pt-eds-1,++I)while(p[pt].x1==I&&pt<=k){ 29 int x1=p[pt].x1,x2=p[pt].x2,y1=p[pt].y1,y2=p[pt].y2,ord=p[pt].ord,X1=x1-1,X2=x2+1,Y1=y1-1,Y2=y2+1; 30 for(int i=max(0,lower_bound(L[X1].begin(),L[X1].end(),(ps){X1,X1,y1,y1,0})-L[X1].begin()-1);i<L[X1].size();++i) 31 if(!(L[X1][i].y1>y2||L[X1][i].y2<y1)){if(L[X1][i].x1<=I)link(L[X1][i].ord,ord);} 32 else if(L[X1][i].y1>y2)break; 33 for(int i=max(0,lower_bound(R[Y1].begin(),R[Y1].end(),(ps){x1,x1,Y1,Y1,0})-R[Y1].begin()-1);i<R[Y1].size();++i) 34 if(!(R[Y1][i].x1>x2||R[Y1][i].x2<x1)){if(R[Y1][i].x1<=I)link(R[Y1][i].ord,ord);} 35 else if(R[Y1][i].x1>x2)break; 36 for(int i=max(0,lower_bound(R[Y2].begin(),R[Y2].end(),(ps){x1,x1,Y2,Y2,0})-R[Y2].begin()-1);i<R[Y2].size();++i) 37 if(!(R[Y2][i].x1>x2||R[Y2][i].x2<x1)){if(R[Y2][i].x1<=I)link(R[Y2][i].ord,ord);} 38 else if(R[Y2][i].x1>x2)break; 39 pt++; 40 } 41 while(q--)scanf("%d%d",&qk,&qx),printf("%d\n",qk?cb[qx]:cf[qx]); 42 }
思路積累:
- 聯通塊的性質
- 離線處理