3.17~3.23
牛客周赛 85
A

签到
#include <bits/stdc++.h>
using namespace std;
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n;
cin >> n;
cout << (n%2 ? "kou\n" : "yukari\n");
return 0;
}
B

贪心
由题目可知,小红和小紫的拿取元素的倾向都是拿尽可能小的元素
因此直接对数组升序排序,然后遍历数组对x进行操作即可
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+1;
int arr[maxn];
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n;
cin >> n;
for(int i=0;i<n;i++)
cin >> arr[i];
int x = 0;
sort(arr,arr+n);
for(int i=0;i<n;i++){
if(i % 2) x -= arr[i];
else x += arr[i];
}
cout << x << '\n';
return 0;
}
C

相邻两个元素不同的情况叫听“突起”
这题有两种突起:10,01
显然,这两种突起最多各只能出现两次,否则就无法挽回大局
遍历数组判断即可
#include <bits/stdc++.h>
using namespace std;
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;
cin >> t;
while(t--){
string s;
cin >> s;
int diff_01 = 0, diff_10 = 0, si = s.size(), pd = 1;
for(int i=0;i<si-1;i++){
if(s[i] != s[i+1]){
if(s[i] == '1')
diff_10++,i++;
else diff_01++,i++;
}
if(max(diff_10,diff_01) > 2){
pd = 0;
break;
}
}
cout << (pd ? "Yes\n" : "No\n");
}
return 0;
}
D

对0和1做一个前缀和,然后首尾双层遍历
i表示删除前i个,j表示从后往前选择的第j个
如果第j个满足双生串的条件,就停止循环,否则一直向前枚举
通过前缀和相减的方式快速算出有几个0或1
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+1;
int n;
double win = 0, defeat = 0;
string s;
int q0[maxn], q1[maxn];
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n >> s;
if(n==1){
cout << "0\n";
return 0;
}
if(s[0] == '0')
q0[0] = 1, q1[0] = 0;
else q0[0] = 0, q1[0] = 1;
for(int i=1;i<n;i++){
q0[i] = q0[i-1] + (s[i] == '0');
q1[i] = q1[i-1] + (s[i] == '1');
}
for(int i=0;i<n;i++){
int pd=1;
for(int j=n-1;j>i;j--){
int n0 = q0[j] - q0[i], n1 = q1[j] - q1[i];
if(!(n0 % 2) && !(n1 % 2) && max(n0,n1)){
win++;
pd = 0;
break;
}
}
if(pd) defeat++;
}
cout << win/(win + defeat) << '\n';
return 0;
}
程协杯&19
B

观察发现,a为偶数甲胜,a为奇数乙胜
#include <bits/stdc++.h>
using namespace std;
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n;
cin >> n;
while(n--){
int a;
cin >> a;
if(a%2 == 0){
cout << "jia wins\n";
}
else cout <<"yi wins\n";
}
return 0;
}
E

考虑上一排怎么到下一排去,假设下一排的无车区间是[L,R],那么能成功从上一排到下一排的位置是[L-K,R+K]
因此从头开始遍历数组,逐排判断即可
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+1;
int L[N],R[N];
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,k;
cin >> n >> k;
for(int i=1;i<=n;i++)
cin >> L[i] >> R[i];
if(n == 1){
cout << "Phoenix\n";
return 0;
}
int old_l,old_r;
int minn = 0, maxn = 1e6;
old_l = max(minn,L[2]-k);
old_r = min(maxn,R[2]+k);
int pd = 1,times;
for(int i=1;i<=n;i++){
old_l = max(old_l,L[i]);
old_r = min(old_r,R[i]);
if(old_l > old_r){
pd = 0;
times = max(2,i);
//cout << L[i] <<' ' << R[i] << '\n';
break;
}
old_l = max(minn,old_l-k);
old_r = min(maxn,old_r+k);
}
if(pd) cout << "Phoenix\n";
else cout << times << '\n';
return 0;
}
G

Set搞定
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+1;
set <int> s;
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n;
cin >> n;
for(int i=0;i<n;i++){
int cache;
cin >> cache;
s.insert(cache);
}
cout << s.size() << '\n';
return 0;
}
J

观察发现,牌的大小从1到nm里,不属于甲的n张牌里的数就是会对甲造成威胁的,假的牌就是"My",不属于甲的牌的数就是"Kong",从1到nm里,遇到一个"My"就My++,遇到一个"Kong"就My--(但是My要大于等于0)
输出My即可
#include <bits/stdc++.h>
using namespace std;
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int m,n;
cin >> m >> n;
int a[51];
for(int i=0;i<n;i++)
cin >> a[i];
sort(a,a+n);
int maxn = n*m , index = 0;
int my=0,kong=0,wins=0;
for(int i=1;i<=maxn;i++){
if(i == a[index]){
wins++;
index++;
}
else{
wins = max(0,wins-1);
}
//cout << wins << '\n';
}
//cout << my << ' '<< kong << '\n';
cout << wins << '\n';
return 0;
}
K

好坑的一道题,我用正常方法怎样都会超时......后来用二分优化,还是Wa,自己造数据debug才发现爆longlong了,于是就出现了if elseif elseif...这一幕
但题还是不难的
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;
cin >> t;
while(t--){
int n,m;
cin >> n >> m;
if(m==1){
cout << "1\n";
continue;
}
if(n < m){
cout << "1\n";
continue;
}
int m_ = 0,m_old=m_;
int mid, l=0, r;
if(m==2) r=33;
else if(m==3) r=20;
else if(m==4) r=16;
else if(m==5) r=14;
else if(m==6) r=12;
else if(m==7) r=11;
else if(m==8) r=10;
else if(m==9) r=10;
else if(m<=11) r=9;
else r=8;
while(l < r){
mid = (l+r) >> 1;
m_ = pow(m,mid);
if(m_ < n)
l = mid+1;
else r = mid;
//cout<<"l:"<<l<<" r:"<<r<<" mid:"<<mid<<" m_:"<<m_<<'\n';
}
if(m_>n){
m_old = m_/m;
if(m_-n >= n-m_old) mid--;
}
if(m_<n){
m_old = m_*m;
if(m_old-n < n-m_) mid++;
}
cout << max(1LL,mid) << '\n';
}
return 0;
}
D

居然BFS搜就行了....
可以知道,走一次k就行,再用一次瞬移就跟没用差不多
遇到k大于0的情况就判断从结束点对面直接到结束点和正常走哪个小
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int inf = 1e8;
const int maxn = 2e5+5;
int n,k,a,b,x,y,ans=0;
int vis[maxn]={0},step[maxn];
void bfs(){
queue <pair<int,int>> q;
q.push({a,0});
while(!q.empty()){
pair<int,int> node = q.front();
q.pop();
if(vis[node.first]) continue;
vis[node.first]++;
step[node.first] = node.second;
q.push({(node.first+x)%n, node.second+1});
q.push({(node.first-y+n)%n, node.second+1});
}
}
signed main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n >> k >> a >> b >> x >> y;
a--,b--;
memset(step,inf,sizeof(step));
bfs();
ans = step[b];
if(k > 0)
ans = min(step[b],step[(b+n/2)%n]+1);
cout << (ans>=inf ? -1 : ans) << '\n';
return 0;
}
I

01背包基础上改的
对于题目玩的花样,我们就做两次dp,一次从前往后做,一次从后往前做,求出,每个点的最优解
01背包的状态转移方程为
dp1[i][j] = max(dp1[i-1][j],dp1[i-1][j-c[i]]+w[i]);(前->后)
dp2[i][j] = max(dp2[i+1][j],dp2[i+1][j-c[i]]+w[i]);(后->前)
然后再遍历一遍n,找到最大的
dp1[i-1][m]+dp2[i+1][m]+w[i]
输出即可
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3+2;
int dp1[maxn][maxn], dp2[maxn][maxn], c[maxn], w[maxn];
int n,m;
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
memset(dp1,0,sizeof(dp1));
memset(dp2,0,sizeof(dp2));
cin >> n >> m;
for(int i=1;i<=n;i++){
int wi,vi;
cin >> wi >> vi;
c[i] = wi;
w[i] = vi;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(j >= c[i])
dp1[i][j] = max(dp1[i-1][j],dp1[i-1][j-c[i]]+w[i]);
else dp1[i][j] = max(dp1[i][j],dp1[i-1][j]);
}
for(int i=n;i>=1;i--)
for(int j=1;j<=m;j++){
if(j >= c[i])
dp2[i][j] = max(dp2[i+1][j],dp2[i+1][j-c[i]]+w[i]);
else dp2[i][j] = max(dp2[i][j],dp2[i+1][j]);
}
int ans = 0;
for(int i=1;i<=n;i++){
ans = max(ans,dp1[i-1][m]+dp2[i+1][m]+w[i]);
}
cout << ans << '\n';
return 0;
}
LG P1135

无意间找到了一题,和程协杯的D真的好像......
都是bfs暴搜
#include <bits/stdc++.h>
using namespace std;
const int inf = 1e6;
int n,a,b;
int step[201],vis[201]={0},room[201]={0};
void bfs(){
queue <pair<int,int>> q;
q.push({a,0});
while(!q.empty()){
pair<int,int> node = q.front();
q.pop();
if(vis[node.first]) continue;
vis[node.first] = 1;
room[node.first] = node.second;
if(node.first+step[node.first] <= n)
q.push({node.first+step[node.first],node.second+1});
if(node.first-step[node.first] >= 1)
q.push({node.first-step[node.first],node.second+1});
}
}
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n >> a >> b;
for(int i=1;i<=n;i++)
cin >> step[i];
if(a == b){
cout << "0\n";
return 0;
}
bfs();
if(room[b] == 0) room[b] = -1;
cout << room[b] << '\n';
return 0;
}

浙公网安备 33010602011771号