Codeforces Round #578 (Div. 2)
Solution
A. Hotelier
題意:
對應(yīng)\(n\)個位置,如果是\(L\),左邊第一個為\(0\)的位置變?yōu)?span id="ozvdkddzhkzd" class="math inline">\(1\),如果是\(R\),右邊第一個為\(0\)的位置變?yōu)?span id="ozvdkddzhkzd" class="math inline">\(1\),如果是數(shù)字,對應(yīng)位置變?yōu)?span id="ozvdkddzhkzd" class="math inline">\(0\)。
思路:
模擬即可。但是比賽就是無語,這么辣雞的題目,竟然用數(shù)字判字符\(0\)……
B. Block Adventure
題意:
一個角色去冒險,有個無窮大的背包,初始有\(m\)個木塊,然后路上都是高度為\(h_i\)的木樁,他站在木樁上,只要下一個木樁與當前高度差\(\leq\ k\),你就能上去,當然你擅長木工,你可以用背包里的木塊使當前木樁變高,也可以每次削減當前木樁高度為1的木塊任意次,(但不能為使當前木樁高度為負)。問你是否可以到達最后的木樁。
思路:
很明顯貪心,每次盡量取最多的木塊放入背包。做這個題的時候很傻,剛開始由于這么定位置,然后用列方程搞定,但是只是腦子里去判的正負,沒有根據(jù)\(x\)的具體值操作,導(dǎo)致自閉。
如果\(h_{i+1}>h_i 并且 h_{i+1}-h_i>k+m\),顯然不行了。若能夠到達下一個,要分是增高還是削減,可以列方程\(x=h_{i+1}-h_i-k\),若\(x>0\),說明要增高\(x\),\(m\)要消耗\(x\),若\(x\leq0\),則判斷是否削減高度大于自身高度,處理即可。
如果\(h_{i+1}\leq\ h_i\),肯定是削減高度,判斷是否削減高度大于自身高度。
比賽改了半年emmmm,最后3分鐘網(wǎng)頁炸了,\(37\)秒的時候文件提交晚了,賽后\(AC\)
C. Round Corridor
題意:
兩個圓盤,內(nèi)圈\((1,1),\ldots,(1,n)\),外圈\((2,1),\ldots,(2,m)\),等分。詢問\((s_x,s_y)\)是否能到達\((e_x,e_y)\)。
很明顯,當\(n,m\)互質(zhì)時,必定可以到達,如果不互質(zhì),畫幾個情況,可以發(fā)現(xiàn)可以把區(qū)域分組,然后判斷即可。
如果是同一圈的判斷,可以判斷是否是同一組,如果不是同一圈的,可以先根據(jù)內(nèi)圈的第幾組算出對應(yīng)外圈可以達到的范圍,再\(check\)一下即可。
//#define DEBUG #include<bits/stdc++.h> using namespace std; #define lson (rt<<1) #define rson (rt<<1|1) const int N=3000010; const int inf=0X3f3f3f3f; const long long INF = 0x3f3f3f3f3f3f3f3f; const double eps = 1e-6; const double pi = acos(-1.0); const int mod = 1000000007; typedef long long ll;ll n,m,q; int main() {scanf("%lld%lld%lld",&n,&m,&q);ll tmp=__gcd(n,m);while(q--) {ll x,a,y,b;scanf("%lld%lld%lld%lld",&x,&a,&y,&b);if(tmp==1) {puts("YES");continue;}ll partn=n/tmp,partm=m/tmp;bool ok=false;if(x==y) {ll part=(x==1)?partn:partm;if(ceil(a*1.0/part)==ceil(b*1.0/part)) ok=true;} else {ll tmpcal=(x==1)?a:b;ll tmpcheck=(x==1)?b:a;ll r=ceil(tmpcal*1.0/partn)*partm;ll l=r-partm+1;if(tmpcheck>=l&&tmpcheck<=r) ok=true;}if(ok) puts("YES");else puts("NO");} }D. White Lines
題意:
給出\(n\times\ n\)的黑白塊矩形,然后你可以最多使用一次\(k\times\ k\)的橡皮擦,你若選中\(ceil(i,j)\),那么以該塊作為左上角的\(k\times\ k\)的矩形塊可變?yōu)榘咨?#xff0c;求操作后最多有幾條白色條狀(一行或一列都為白色即為白色條狀)
思路:
首先從行考慮,若都為白色,直接計入答案。否則判斷最左和最右的長度是否\(\leq k\),不是的話,沒有貢獻,若是的話,把所有能覆蓋這段的塊貢獻+1。考慮列也是相同作法,然后求所有塊的最大值即可。但是增加貢獻用直接賦值的話,復(fù)雜度O(n_3),不過好像能過。我們可以用二維差分的思想來求
再次學(xué)習(xí)差分思想+前綴和。
一維差分,令\(d_i=a_i-a_{i-1}\),然后可以根據(jù)\(d\)數(shù)組,得到\(a\)數(shù)組,因為\(a_i=d_1+d_2+,\ldots,+d_i\),即原數(shù)組等于差分數(shù)組的前綴和
即\(a_i=(a_1-a_0)+(a_2-a_1)+,\ldots,+(a_i-a_{i-1})\)
若將\(a\)數(shù)組\(L\sim\ R+x\),只需\(d_L+x,d_R-x\)即可。見圖二維的我們也可以差分。
求紅色矩陣的面積,首先二維前綴和處理出到左上角的面積。然后\(S_紅=S_{整個面積}-(S_藍+S_紫)-(S_綠+S_紫)+S_紫\)
對應(yīng)公式就是\(sum[x_2][y_2]-sum[x_2][y_1-1]-sum[x_1-1][y_2]+sum[x_1-1][y_1-1]\)。
其中\(sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]\)
考慮一維差分是從區(qū)間開始位置和結(jié)束位置修改,對于二維:
若將綠色部分增加\(x\),我們可以這樣修改\(a[x_1][y_1]+=x,a[x_2+1][y_1]-=x,a[x_1][y_2+1]-=x,a[x_2+1][y_2+1]+=x\),
若將\((x_1,y_1)+=x\),那么一直到右下角都會被影響,所以我們可以讓藍色部分一直到右下角都減\(x\),粉色部分一直到右下角都減\(x\),這樣紫色部分多減了一次,我們讓紫色部分再加\(x\),即可。
然后根據(jù)差分性質(zhì),求二維前綴和即可知道每一個位置的值。
對于這道題,我們可以求出有貢獻的矩形范圍,然后差分思想修改,最后二維前綴和取每個位置最大值即可。
//#define DEBUG #include<bits/stdc++.h> using namespace std; #define lson (rt<<1) #define rson (rt<<1|1) const int N=100010; const int inf=0X3f3f3f3f; const long long INF = 0x3f3f3f3f3f3f3f3f; const double eps = 1e-6; const double pi = acos(-1.0); const int mod = 1000000007; typedef long long ll;char g[2010][2010]; int dif[2010][2010];int main() {#ifdef DEBUGfreopen("in.txt","r",stdin);#endifint n,k,sum=0;scanf("%d%d",&n,&k);for(int i=1;i<=n;i++) {scanf("%s",g[i]);}for(int i=1;i<=n;i++) {int st=-1,ed=-1;for(int j=0;j<n;j++) {if(g[i][j]=='B') {if(st==-1) st=j+1;ed=j+1;}}if(st==-1) sum++;else if(ed-st+1<=k) {int lx=max(1,i-k+1),ly=max(1,ed-k+1);int rx=i,ry=st;dif[lx][ly]++;dif[lx][ry+1]--;dif[rx+1][ly]--;dif[rx+1][ry+1]++;}}for(int j=0;j<n;j++) {int st=-1,ed=-1;for(int i=1;i<=n;i++) {if(g[i][j]=='B') {if(st==-1) st=i;ed=i;}}if(st==-1) sum++;else if(ed-st<=k) {int lx=max(1,ed-k+1),ly=max(1,j+1-k+1);int rx=st,ry=j+1;dif[lx][ly]++;dif[lx][ry+1]--;dif[rx+1][ly]--;dif[rx+1][ry+1]++;}}int ans=-1;for(int i=1;i<=n;i++) {for(int j=1;j<=n;j++) {dif[i][j]=dif[i][j]+dif[i][j-1]+dif[i-1][j]-dif[i-1][j-1];}}for(int i=1;i<=n;i++) {for(int j=1;j<=n;j++) {ans=max(ans,dif[i][j]);}}printf("%d\n",sum+ans); }E. Compress Words
題意:
壓縮單詞,前面后綴和后面前綴有公共部分就壓縮。
思路:
\(KMP\)裸題,不過文本串匹配位置可以用最大壓縮位置開始,發(fā)現(xiàn)之前的題白做了,復(fù)習(xí)一下\(KMP\)。
\(Next[i]\)表示\(i\)之前,前綴和后綴相同的最大值。
比如\(ababc\),\(Next\)數(shù)組為\(\{-1,0,0,1,2\}\)
簡要梳理,\(Next\)數(shù)組的求法,根據(jù)模式串與模式串匹配遞推得出。
如果\(t[i]==t[j]\),那么\(Next[++i]=++j\),意會emmm
匹配就不相等\(j=Next[j]\),相等就都后移。
這道題就直接匹配,返回的\(j\)值,即能匹配成功的最后位置的下一位。
//#define DEBUG #include<bits/stdc++.h> using namespace std; #define lson (rt<<1) #define rson (rt<<1|1) const int N=100010; const int inf=0X3f3f3f3f; const long long INF = 0x3f3f3f3f3f3f3f3f; const double eps = 1e-6; const double pi = acos(-1.0); const int mod = 1000000007; typedef long long ll;int n; string ans; string s;int Next[N*10]; void prekmp(string s) {int j=Next[0]=-1;int i=0;int len=s.size();while(i<len) {while(j!=-1&&s[i]!=s[j]) j=Next[j];Next[++i]=++j;} }int kmp(int pos) {int i=pos,j=0;int lenans=ans.size();while(i<lenans) {if(j==-1||ans[i]==s[j]) {i++;j++;} else j=Next[j];}return j; }int main() {#ifdef DEBUGfreopen("in.txt","r",stdin);#endifscanf("%d",&n);cin>>ans;for(int i=2;i<=n;i++) {cin>>s;prekmp(s);int pos=kmp(max(0,(int)ans.size()-(int)s.size()));for(int j=pos;j<s.size();j++) ans+=s[j];}cout<<ans<<'\n'; }轉(zhuǎn)載于:https://www.cnblogs.com/ACMerszl/p/11373387.html
總結(jié)
以上是生活随笔為你收集整理的Codeforces Round #578 (Div. 2)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2019百度之星初赛1
- 下一篇: Java Web学习(三)数据加密方式详