牛客练习赛80
总结: A了三题,凭着手速冲上了前50,这场的神仙估计都参加春招去了,榜首才出了4题,活久见。
A. 加密
很常规的简单模拟,大方向是先算出由1形成的段共几段,然后通过一次反转至多可以减少掉一个1子串。考虑几种情况:
- 当两个连续的1形成的块中间隔了超过1个0时,将中间的0直接反之显然没什么意义。
- 当两个连续的1形成的块中间隔了1个0时,将中间的0反转即可减少一个子串。
- 当有一个1两边都是0的时候,将这个1反转也能减少1个子串。
- 当1出现在最左侧或者最右侧的时候,只要旁边的是0也能消除一个子串。
代码:
#include <bits/stdc++.h>
#define ll long long
#define mem(f,x) memset(f,x,sizeof(f))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
#define pk push_back
using namespace std;
const int M = 1e6+5;
const int N = 1e6+5;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
int m, n;
char s[N];
int main( ){
while( scanf( "%s", s ) != EOF ){
n = strlen(s);
bool flag = 0;
int i = 0, cnt = 0;
while( i < n ){
if( s[i] == '0' ){
if( i && i < n-1 && s[i-1] == '1' && s[i+1] == '1')
flag = 1;
i++;
}
else{
if( i && i < n-1 && s[i-1] == '0' && s[i+1] == '0' )
flag = 1;
if( !i && s[i+1] == '0' )
flag = 1;
if( i == n-1 && s[i-1] == '0' )
flag = 1;
cnt++;
while( i < n && s[i] == '1' )
i++;
}
}
printf( "%d\n", cnt-flag );
}
return 0;
}
B. 卷积
很容易想到,当 i>2 时Ci必定为0,因为无论选哪两个数,都不可能满足未出现的最小的下标大于2。因此只需要讨论i = 0,1,2时的情况。
- i = 0时,可以选a中下标大于1的任何数和b中下标大于0的任何数
- i = 1时,有三种选法:{a[0],b[0]};{a[0],b[j]};{a[j],b[0]} 其中j > 1
- i = 2时,有两种选法:{a[0],b[2]};{a[2],b[0]}
代码:
#include <bits/stdc++.h>
#define ll long long
#define mem(f,x) memset(f,x,sizeof(f))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
#define pk push_back
using namespace std;
const int M = 1e5+5;
const int N = 1e5+5;
const ll MOD = 998244353;
const int INF = 0x3f3f3f3f;
int m, n;
ll a[N], b[N];
int main( ){
while( scanf( "%d", &n ) != EOF ){
ll suma = 0, sumb = 0;
for( int i = 0; i < n; i++ ){
scanf( "%lld", a+i );
suma = (suma+a[i])%MOD;
}
for( int i = 0; i < n; i++ ){
scanf( "%lld", b+i );
sumb = (sumb+b[i])%MOD;
}
if( n == 1 ){
printf( "0\n" );
continue;
}
if( n == 2 ){
printf( "%lld %lld\n", a[1]*b[1]%MOD, a[0]*b[0]%MOD );
continue;
}
ll ans1 = ((suma-a[0]+MOD)%MOD)*((sumb-b[0]+MOD)%MOD)%MOD;
ll tmp1 = (a[0]*b[0])%MOD;
ll tmp2 = a[0]*(((sumb-b[0]+MOD)%MOD-b[1]+MOD)%MOD)%MOD;
ll tmp3 = b[0]*(((suma-a[0]+MOD)%MOD-a[1]+MOD)%MOD)%MOD;
ll ans2 = (tmp1+tmp2+tmp3)%MOD;
ll ans3 = (a[0]*b[1]%MOD+a[1]*b[0]%MOD)%MOD;
printf( "%lld %lld %lld", ans1, ans2, ans3 );
for( int i = 3; i < n; i++ )
printf( " 0" );
printf( "\n" );
}
return 0;
}
C. 不降数
先可暴力打表,我自己是把n = 1,2,3,4,5下的答案打表打出来了,后面发现的规律是 f(n) = C(n+8, 8)。
代码:
#include <bits/stdc++.h>
#define ll long long
#define mem(f,x) memset(f,x,sizeof(f))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
#define pk push_back
using namespace std;
const int M = 1e6+5;
const int N = 1e6+5;
const int MOD = 100019;
const ll inv = 78440;
const int INF = 0x3f3f3f3f;
ll m, n;
ll q_pow( ll x, ll y ){
x %= MOD;
ll ret = 1;
while( y ){
if( y&1 ) ret = (ret*x)%MOD;
x = x*x%MOD;
y >>= 1;
}
return ret;
}
int main( ){
/*ll fm = 1;
for( int i = 1; i <= 8; i++ )
fm = fm*i%MOD;
cout << q_pow( fm, MOD-2 ) << endl;*/
while( scanf( "%lld", &n ) != EOF ){
ll sum = 1;
for( int i = 1; i <= 8; i++ )
sum = sum*(n+i)%MOD;
sum = sum*inv%MOD;
printf( "%lld\n", sum );
}
return 0;
}