B 牛牛想起飞

牛客2020跨年场题解_#include

题解
DP问题,dp[i][j]表示前i个数中是否有%m为j的数,有为1,否则为0。
官方题解

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL N = 500010, M = 100;
int dp[N][M],a[N],b[N];

int main()
{
LL n, m, res = 0,sum1 = 0;
scanf("%lld%lld", &n, &m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum1 =(sum1 + a[i]) % m;

}
dp[0][sum1] = 1;
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
dp[i][sum1] = 1;

}

for(int i = 1; i <= n; i++)
{
for(int j = 0; j < m; j++)
{
if(dp[i - 1][j] == 1)
{
dp[i][(j + b[i]) % m] = 1;
dp[i][(j - b[i]) % m] = 1;
dp[i][j] = 1;
}

}
}
for(int j = m - 1; j >= 0;j --)
{

if(dp[n][j] == 1)
{
printf("%d",j);
break;
}
}

return 0;
}

牛客2020跨年场题解_#include_02

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
using namespace std;
const int N = 1e5 + 5;
int a[N], b[N];
bool dp[N][3][105]; // 不变化 加b[i] 减b[i] %y意义下最大
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int n, y;
cin >> n >> y;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++) cin >> b[i];
memset(dp, false, sizeof(dp));
dp[0][0][0] = true;
for (int i = 1; i <= n; i++) {
for (int k = 0; k < y; k++) {
vector<int> v;
v.emplace_back(0);
v.emplace_back(-b[i]);
v.emplace_back(b[i]);
for (int j = 0; j < 3; j++) {
dp[i][0][k] |= dp[i - 1][j][((k - a[i] - v[0]) % y + y) % y];
dp[i][1][k] |= dp[i - 1][j][((k - a[i] - v[1]) % y + y) % y];
dp[i][2][k] |= dp[i - 1][j][((k - a[i] - v[2]) % y + y) % y];
}
}
}
int ans = 0;
for (int k = 0; k < y; k++) {
for (int j = 0; j < 3; j++) {
if (dp[n][j][k]) {
ans = k;
}
}
}
cout << ans << '\n';
return 0;
}

最小互质数

牛客2020跨年场题解_#include_03


题解

最小出现且没有出现在给出数的因子的素数即可。

线性筛求因子即可。

注意1的特殊情况

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 100010;

int primes[N], cnt;
int minp[N];
bool st[N];

void get_primes(int n)
{
for (int i = 2; i <= n; i ++ )
{
if (!st[i])
{
minp[i] = i;
primes[cnt ++ ] = i;
}
for (int j = 0; primes[j] * i <= n; j ++ )
{
int t = primes[j] * i;
st[t] = true;
minp[t] = primes[j];
if (i % primes[j] == 0) break;
}
}
}
int h[N * 2];
bool judge(int n)
{
if(n == 1) return 1;
for(int i = 2; i * i <= n; i++)
{
if(n % i == 0)return 0;
}
return 1;
}
int main()
{
get_primes(N - 1);


int x;
int n;
scanf("%d", &n);
int flag = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d", &x);
if(x == 1) flag = 1;
while (x > 1)
{
int p = minp[x];
h[p] = 1;
while (x % p == 0)
{
x /= p;
h[x] = 1;
}
}
}
if(flag == 0)
{
cout<<1<<endl;
return 0;
}
for(int i = 1; ;i++)
{
if(h[i] == 0 && judge(i) == 1)
{
cout<< i<<endl;
break;
}
}

return 0;
}

牛客2020跨年场题解_#include_04

E 牛牛的反函数

牛客2020跨年场题解_#include_05


题解

找规律

注意答案不能超过1e18。

y奇数时,最小的x= 2^(y/2)+2,

y偶数时,最小的x=2^(y/2-1)+ 1

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 100010;

int primes[N], cnt;
int minp[N];
bool st[N];
LL dfs(LL n)
{
if(n == 1) return n;
if(n != 1 && n % 2 == 1) return dfs(n + 1) + 1;
return dfs(n/2) + 1;
}
LL qmi(LL a, LL b)
{
LL res = 1;
while (b)
{
if (b & 1) res = res * a;
a = a * (LL)a;
b >>= 1;
}
return res;
}


int main()
{
//cout<<qmi(2,60)<<endl;
/*for(LL i = 1; i <= 100; i++)
{
cout<<"f("<<i<<")="<<dfs(i)<<endl;
}*/
int T;
cin>>T;
while(T--)
{
LL n;
scanf("%lld",&n);

if(n == 1){
cout<<1<<endl;
continue;
}
if(n % 2 == 1)
{

if((n + 1)/2 - 1> 62)
{
printf("-1\n");
}
else
{
LL res = qmi(2, (n + 1)/2 - 1)+2;
if(res > 1e18)
{
res = -1;
}
printf("%lld\n",res);
}

}
else
{
if((n )/2 - 1> 62)
{
printf("-1\n");
}
else
{

LL res = qmi(2, n/2 - 1)+1;
if(res > 1e18)
{
res = -1;
}
printf("%lld\n",res);
}

}


}
return 0;
}

牛客2020跨年场题解_#include_06

D 衔尾蛇

牛客2020跨年场题解_#include_07


示例1

输入

复制

1 1 1

输出

复制

8

说明

一条红蛇咬自己,一种方案。

一条蓝蛇咬自己,一种方案。

一条绿蛇咬自己,一种方案。

一条红蛇和一条蓝蛇互相咬对方的尾巴,一种方案。

一条红蛇和一条绿蛇互相咬对方的尾巴,一种方案。

一条绿蛇和一条蓝蛇互相咬对方的尾巴,一种方案。

三条蛇互相咬,红咬绿,绿咬蓝,蓝咬红,一种方案。

三条蛇互相咬,红咬蓝,蓝咬绿,绿咬红,一种方案。

一共8种方案。

示例2

输入

复制

1 0 0

输出

复制

1

说明

一条红蛇咬自己,显然只有这一种方案。

示例3

输入

复制

3 0 0

输出

复制

3

说明

一条红蛇咬自己,一种方案。

两条红蛇互相咬对方的尾巴,为一种方案。

三条红色互相咬,也是一种方案(1咬2的尾巴,2咬3的尾巴,3咬1的尾巴)

题解
dfs暴力,判重方法可以用环形字符串的方式

#include <bits/stdc++.h>
#define ll long long
using namespace std;
map<string,bool> mp;
int a,b,c,ans;
void solve(string s){
if(!mp[s]){
ans++;
int len=s.size();
for(int i=0;i<len;i++){
string p="";
for(int j=i;j<len;j++) p+=s[j];
for(int j=0;j<i;j++) p+=s[j];
mp[p]=1;
}
}
}
void dfs(int x,int y,int z,string s){
if(s.size()) solve(s);
if(x<a) dfs(x+1,y,z,s+'a');
if(y<b) dfs(x,y+1,z,s+'b');
if(z<c) dfs(x,y,z+1,s+'c');
}
int main(){
scanf("%d%d%d",&a,&b,&c);
dfs(0,0,0,"");
printf("%d",ans);
}

牛客2020跨年场题解_i++_08

#include<bits/stdc++.h>
using namespace std;
set<string>s;
int main(){
int a,b,c,i,j,k,z,cnt=0;;
cin>>a>>b>>c;
int sum=1;
int n=a+b+c;
for(j=1;j<=n;j++){ //枚举长度为j
sum*=3;
for(i=0;i<sum;i++){ //共i种状态
int p=i,ca=0,cb=0,cc=0;
string temp="";
for(k=0;k<j;k++){ //p转为三进制代表状压值
if(p%3==0)temp+='a',ca++;
if(p%3==1)temp+='b',cb++;
if(p%3==2)temp+='c',cc++;
p/=3;
}
if(ca>a||cb>b||cc>c)continue; //判断合法

for(k=0;k<j;k++){ //判重
string ttemp="";
for(z=k;z<k+j;z++){
ttemp+=temp[z%j];
}
if(s.count(ttemp))break;
}
if(k==j){
s.insert(temp);
// Ouroboros->hikari->tairitsu->kou
cnt++;
}
}
}
cout<<cnt;

}

H 牛清楚的裙子!!!

牛客2020跨年场题解_#include_09


题解

牛客2020跨年场题解_#include_10


牛客2020跨年场题解_ci_11

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e7 + 5;
double f[maxn];
int main()
{
for(int i=1;i<=10000000;i++) f[i] = f[i-1] + 1.0/i;
int T; cin>>T;
while(T--)
{
int n; scanf("%d", &n);
double ans = (n-1) * f[n] + f[n] * 10000;
printf("%.7f\n", ans);
}
}