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;
}