牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)
A题:直接模拟就可以了,用cnty,cnto,cntu记录字符的个数,判断每一个2*2的小矩阵里面如果
cnty,cntu,cnto都大于0的话就把答案++
#include
using namespace std;
typedef long long ll;
const int N=310;
int vis[1001][1001];
int pos[N];
int a[N];
int cnty,cntu,cnto;
char w[1001][1001];
void cf()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
char c;
cin>>c;
w[i][j]=c;
}
}
int p=0;
for(int i=1;i<=n-1;i++)
{
for(int j=1;j<=m-1;j++)
{
cnty=0;
cntu=0;
cnto=0;
if(w[i][j]=='y')cnty++;
else if(w[i][j]=='u')cntu++;
else if(w[i][j]=='o')cnto++;
if(w[i][j+1]=='y')cnty++;
else if(w[i][j+1]=='u')cntu++;
else if(w[i][j+1]=='o')cnto++;
if(w[i+1][j]=='y')cnty++;
else if(w[i+1][j]=='u')cntu++;
else if(w[i+1][j]=='o')cnto++;
if(w[i+1][j+1]=='y')cnty++;
else if(w[i+1][j+1]=='u')cntu++;
else if(w[i+1][j+1]=='o')cnto++;
if(cnty>0&&cntu>0&&cnto>0)p++;
}
}
cout<
B题这种01串的题目挺常见的
因为最后相连的字符都不同所以就是说肯定是01010101这样
所以我们把长度为n的字符分别构造出两种:010101...和1010101...这样然后分别计算把原字符串改成这两串的代价,取两个的min就可以
#include
using namespace std;
typedef long long ll;
const int N=310;
int vis[1001][1001];
int pos[N];
int a[N];
int cnty,cntu,cnto;
char w[1001][1001];
void cf()
{
int n;
string s;
cin>>s;
n=s.size();
string s1,s2;
for(int i=0;i
C题:因为区间范围是l-r最大的话肯定尽量都是l
所以答案就是max=(b-a)/l
min=(b-a+r-1)/r//这里加r-1是上取整操作,如果说mod r还有余数的话我们就去再加一个数而不是把倒一的数去取比r小的数,因为这里要操作数最大,所以我们尽量去多加数
至于max的话l也可能不会整除但是我们可以倒一个数不取l取l+(b-a)%l这样答案就还是(b-a)/l
这里大家可能会问了,那如果余数不够呢
我们知道mod l的余数最大是l-1
如果说区间(r-l)小于l-1的话那说明((b-a)/l和(b-a)/ r)这两个的结果是一样的,在有余数的情况下((b-a)+r-1)/r由于上取整最后的答案是会比(b-a)/l大的也就是说min>max这是不可能的,这种情况下我们就无法得到答案,那就是-1,也就是说min>max这个条件是看余数是不是会比区间大,也就可以解决我们余数判断的疑惑了
#include
using namespace std;
typedef long long ll;
const int N=310;
int vis[1001][1001];
int pos[N];
//int a[N];
int cnty,cntu,cnto;
char w[1001][1001];
int ans[100][100];
void cf()
{
ll a,b,l,r;
cin>>a>>b>>l>>r;
ll tmp=b-a;
ll k=tmp/l;//因为如果不能整除的话我们可以把倒二个l换成一个可能比l大的数
ll q=(tmp+r-1)/r;//上取整如果不够的话必须多拿一个数
if(k>t;
while(t--)
{
cf();
}
}
D题
其实后导0做法是挺常见的
就是看min(2因子,5因子)
2因子和5因子两个数里面较小的那个数决定了两个数相乘后0的个数
这题我们可以开一个ans[i][j]表示数里面2的因子有i个,5的因子有j个的数的个数
当两个数相乘的时候,其实就是把两个数2的因子个数相加,5的因子个数相加
然后0的个数就是两个因子个数取min就是了
举了例子把125*8
125:2的因子个数:0,5的因子个数3个
8:2的因子3个,5的因子0个
两个相乘之后2的因子0+3
5的因子3+0
最后得数x:2的因子3个,5的因子3个
min(3,3)=3所以最后后导0就有3个
当然ans[i][j]可能有很多个,也就是说有相同i个2因子和j个5因子的数之间是可以相乘的,
不同2因子和5因子之间也可以相乘
也就是说我们要处理两种情况
注意最后答案是要/2的因为是无序乘的结果会被算两个比如x*y和y*x本来是一种但是我们就会算成两种
#include
using namespace std;
typedef long long ll;
const int N=310;
int vis[1001][1001];
int pos[N];
//int a[N];
int cnty,cntu,cnto;
int ans[100][100];
void cf()
{
int n,w;
cin>>n>>w;
vectorb(n+1);
for(int i=1;i<=n;i++)
{
cin>>b[i];
}
for(int i=1;i<=n;i++)
{
int c1=0,c2=0;
while(b[i]%2==0)
{
b[i]/=2;
c1++;
}
while(b[i]%5==0)
{
b[i]/=5;
c2++;
}
ans[c1][c2]++;//表示有c1个2因子和c2跟5因子的数有多少个
}
ll sum=0;
for(int i=0;i<=30;i++)
{
for(int j=0;j<=30;j++)
{
if(ans[i][j])
{
//同时2和5因子个数相同的数自己可以*
if(min(i+i,j+j)>=w)
{
sum+=(ans[i][j])*(ans[i][j]-1);
}
}
for(int p=0;p<=30;p++)
{
for(int q=0;q<=30;q++)
{
if(p==i&&q==j)continue;
if(min(i+p,j+q)>=w)
{
sum+=(ans[i][j]*ans[p][q]);
}
}
}
}
}
cout<
这里的循环30是看数据范围算出最多有多少个2因子和5因子,