Codeforces Round #472 A-D
A. Tritonic Iridescence
題意:使用CMY對字串進行填充,要求相鄰的兩個不能相同,如果有兩種以上可行填充方法就輸出“YES”否則輸出“NO”。
思路:對每一個問號進行判定,最後的結果就是所有問號的可行方案數的乘積,當然可能會超出資料範圍,因此只要大於2不再變大。此外, 還要判斷是否有連續兩個相同。
AC程式碼:
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <string> #include <vector> #include <set> using namespace std; #define FSIO ios::sync_with_stdio(0);cin.tie(0); #define DEBUG(a) cout<<"DEBUG: "<<(a)<<endl; const int MAXN = 105; const int MOD = 1e9+7; const int INF = 1e9+7; char str[MAXN]; set<char> gg; int n; int main() { //FSIO; while(cin>>n) { scanf(" %s",str+1); int flag = 0; int res = 0; for(int i=1;i<=n;++i) { if(str[i]=='?') { if(!res) res=1; gg.clear(); if(i>1&&str[i-1]!='?') gg.insert(str[i-1]); if(i<n&&str[i+1]!='?') gg.insert(str[i+1]); if(res>=2) res = 3; else res = res*(3-gg.size()); } else if(i<n&&str[i]==str[i+1]) {flag=1; break;} } if(!flag&&res>=2) cout<<"Yes"<<endl; else cout<<"No"<<endl; } return 0; }
B. Mystical Mosaic
題意:給定一種操作,即對於某非空的正整數集合的集合R,C,對於R_i和C_i,填充網格中R_i行與C_i列相交點為黑色,且R和C中任意兩集合互斥。對於某網格,如能從空白網格經這樣的操作變成該網格則輸出“Yes”,否則輸出“No”。
思路:因為每一個點都要進行判定,不妨從左上角開始掃描,對於存在黑格的行進行掃描,取其中的所有為黑格的對應列,再對所有列往下逐行掃描,若這些列在某行存在黑格,則所有列都必須有才行。之後標記已經掃描過的行列以及格子,只要遇到已經標記的行列就不行,否則則行。
AC程式碼:
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <string> #include <vector> #include <set> using namespace std; #define FSIO ios::sync_with_stdio(0);cin.tie(0); #define DEBUG(a) cout<<"DEBUG: "<<(a)<<endl; const int MAXN = 55; const int MOD = 1e9+7; const int INF = 1e9+7; char mapp[MAXN][MAXN]; int mkr[MAXN]; int mkc[MAXN]; int n, m; int cntblack; int walk(int x, int y) { vector<int> tmpp; for(int t=y; t<=m; ++t) if(mapp[x][t]=='#') { if(!mkc[t]) { mkc[t] = 1; mapp[x][t]='.'; cntblack--; tmpp.push_back(t); } else return 0; } vector<int> tomark; for(int j=x+1; j<=n; ++j) { int cnt = 0; for(int i=0;i<tmpp.size();++i) { if(mapp[j][tmpp[i]]=='#') { cnt++; if(!mkr[j]) { tomark.push_back(j); mapp[j][tmpp[i]]='.'; cntblack--; } else return 0; } } if(cnt&&cnt!=tmpp.size()) return 0; } for(int i=0; i<tomark.size(); ++i) mkr[tomark[i]] = 1; return 1; } int solve() { memset(mkr,0,sizeof(mkr)); memset(mkc,0,sizeof(mkc)); for(int i=1; i<=n; ++i) { for(int j=1; j<=m; ++j) { if(mapp[i][j]=='#') { if(!mkr[i]&&!mkc[j]) { if(!walk(i,j)) return 0; } else return 0; /*cout<<endl; for(int mi=1;mi<=n;++mi) { for(int mj=1;mj<=m;++mj) cout<<mapp[mi][mj]; cout<<endl; }*/ } } } return 1; } int main() { FSIO; while(cin>>n>>m) { cntblack = 0; for(int i=1; i<=n; ++i) for(int j=1; j<=m; ++j) { cin>>mapp[i][j]; if(mapp[i][j]=='#') cntblack++; } if(solve()&&cntblack==0) cout<<"Yes"<<endl; else cout<<"No"<<endl; } return 0; }
C. Three-level Laser
題意:在含n個數字的升序序列E中,依次選擇三個下標i,j,k,使得i<j<k,且E_i + U<=E_k,輸出最大的(E_k - E_j) / (E_k - E_i)。
思路:對於某個E_i來說,要使得該商最大,j肯定為i+1,而k肯定是滿足要求的最大下標。所以對序列E進行一次掃描判斷每個i的最大對應k即可。最後遍歷一遍E求最大該商。
AC程式碼如下:
#include <iostream> #include <iomanip> #include <algorithm> #include <cstring> #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <string> #include <vector> #include <set> using namespace std; #define FSIO ios::sync_with_stdio(0);cin.tie(0); #define DEBUG(a) cout<<"DEBUG: "<<(a)<<endl; const int MAXN = 100005; const int MOD = 1e9+7; const int INF = 1e9+7; int n, U; int engery[MAXN]; int matters[MAXN]; int main() { //FSIO; while(scanf("%d%d",&n,&U)!=EOF) { for(int i=1;i<=n;++i) scanf("%d",engery+i); double ans = -1; int cur = 1; memset(matters,-1,sizeof(matters)); for(int i=1;i<=n;++i) { while(engery[i]-U>engery[cur]&&cur<=n) { matters[cur] = i-1; cur++; } } for(;cur<=n;++cur) matters[cur] = n; /*for(int i=1;i<=n;++i) cout<<matters[i]<<" "; cout<<endl;*/ for(int i=1;i+2<=n;++i) { if(matters[i]>i+1) { ans = max(ans, (double)(engery[matters[i]]-engery[i+1])/(double)(engery[matters[i]]-engery[i])); } } printf("%.10f\n",ans); } return 0; }
D. Riverside Curio
題意:主角每天對河流水位進行標記,相同水位不重複標記。給定每天的在河流水位上的標記數,求最小的所有天的河流水位下的標記數之和。
思路:對於某天來說,水位下的標記數 = 總的標記數 - 1 - 河流水位上的標記數。
所以,只需要求最小的每天的標記數即可。而對於某天在水位上的標記數來說,總的標記數的最小值即該數 + 1,而相鄰兩天的標記總數最多加一個。所以只需按照上述規則進行貪心地求每天的最小標記數即可,最後對相鄰兩天差大於1的進行貪心地處理(即順次遞減)。最後遍歷陣列求和即可。
AC程式碼如下:
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>
using namespace std;
#define FSIO ios::sync_with_stdio(0);cin.tie(0);
#define DEBUG(a) cout<<"DEBUG: "<<(a)<<endl;
const int MAXN = 100005;
const int MOD = 1e9+7;
const int INF = 1e9+7;
long long level[MAXN];
long long minlevel[MAXN];
long long n;
int main()
{
FSIO;
while(cin>>n)
{
for(long long i=1;i<=n;++i)
cin>>level[i];
minlevel[1] = 1;
for(long long i=2;i<=n;++i)
{
if(minlevel[i-1]-1>=level[i]) minlevel[i] = minlevel[i-1];
else
{
long long tmp = 1;
while(minlevel[i-1]-1+tmp<level[i]) tmp++;
minlevel[i] = minlevel[i-1]+tmp;
for(long long j=0;j<tmp;++j)
minlevel[i-j] = minlevel[i]-j;
}
}
for(int i=n;i>1;--i)
{
if(minlevel[i]-minlevel[i-1]>1)
minlevel[i-1] = minlevel[i]-1;
}
/*for(long long i=1;i<=n;++i)
cout<<minlevel[i]<<" ";
cout<<endl;*/
long long ans = 0;
for(long long i=1;i<=n;++i)
ans = ans + (minlevel[i]-1-level[i]);
cout<<ans<<endl;
}
return 0;
}