文章目录
- N. Fixing the Expression
- 思路
- code
- J. Waiting for...
- 思路
- code
- C. DIY
- 思路
- code
- L. Bridge Renovation
- 思路
- code
- A. Bonus Project
- 思路
- code
- G. Guess One Character
- 思路
- code
- B. Make It Equal
- 思路
- code
N. Fixing the Expression
思路
签到题,只改变中间的字符即可
code
void solve(){int a,b;char o;cin >> a >> o >> b;if(a>b){cout << a << ">" << b << endl;}else if(a<b){cout << a << "<" << b << endl;}else cout << a << "=" << b << endl;return ;
}
J. Waiting for…
思路
签到题,如果读入的是P字符,将候车人数累加
如果读入为B字符,分2种情况:
- 候车的人都能上车并且剩余的空座位大于等于一,输出YES
- 反之,将候车人数减去空座位的数量,输出NO
code
int a=0;
void solve(){char o;int n;cin >> o >> n;if(o=='P') a+=n;else{int sum=n-a;if(sum>=1){a=0;cout << "YES" << endl;}else{a-=n;cout << "NO" << endl;}}return ;
}
C. DIY
思路
将成对的数进行排序,找出其中第一小的数、第二小的数、第一大的数、第二大的数
输出这些数即可
code
void solve(){int n;cin >> n;vector<int> v;map<int,int> m;int sum=0;for(int i=1;i<=n;++i){int x;cin >> x;m[x]++;} for(auto i : m){if(i.se>=2){sum+=i.se/2;if(i.se & 1){for(int j=1;j<=i.se-1;++j) v.push_back(i.fi);}else{for(int j=1;j<=i.se;++j) v.push_back(i.fi);}}}if(sum<4){cout << "NO" << endl;return ;}sort(v.begin(),v.end());int len=v.size();int a1=v[0],a2=v[2],a3=v[v.size()-1-2],a4=v[v.size()-1];cout << "YES" << endl;cout << a1 << " " << a2 << " " << a1 << " " << a4 << " " << a3 << " " << a2 << " " << a3 << " " << a4 << endl;return ;
}
L. Bridge Renovation
思路
先拼18 18 21 和 21 21 18
最多会剩下1 2 个木板,在让剩下的木板和25拼,最后向上取整
code
void solve(){int n;cin >> n;int ans=n*2/3;int k=n*2%3+n;cout << ans+(k+1)/2 << endl; return ;
}
A. Bonus Project
思路
由于每个人都想让自己获利最多,那么排在前面的工程师有最佳选择权
先算出每个工程师最大的工作单位c,接下来判断工程师会不会罢工:
- 累加所有工程师最大的工作单位c,如果比k小,全部输出0
- 反之,倒着遍历数组,最后面的工程师干的工作单位c最多
当工程师需要干的工作单位等于k时,结束循环
最后正序遍历数组即可
code
const int N=1e6+5;
int a[N],b[N],c[N],ans[N];
void solve(){int n,k,sum=0;cin >> n >> k;for(int i=1;i<=n;++i) cin >> a[i];for(int i=1;i<=n;++i) cin >> b[i];for(int i=1;i<=n;++i){c[i]=a[i]/b[i];sum+=c[i];}if(sum<k){for(int i=1;i<=n;++i) cout << 0 << " ";return ;}for(int i=n;i>=1;--i){if(k>=c[i]){ans[i]=c[i];k-=c[i];}else{ans[i]=k;break;}}for(int i=1;i<=n;++i) cout << ans[i] << " ";return ;
}
G. Guess One Character
思路
一道很有意思的思维题
对于3次询问确定一个值,很显然要我们去确定第一个字符或者最后一个字符
设 a = “1” 子串的个数 b= “11” 子串的个数
a-b 相当于将字符串去重,将连续的1变为单个1
例如:
11010111
a = 6
b = 3
a-b=3,字符串为10101
然后查询01子串的个数,设01子串的个数为c
如果a=b+c,则说明第一个字符为0
反之,第一个字符为1
怎么得来的?,让我们接着看这个样例
10101,显然01的个数为2, 2 + 3 ! = 6 2+3!=6 2+3!=6
如果我们将第一个字符1改为0,字符串为01010111
a=5
b=2
a-b,则字符串为010101
显然01的个数为3,2+3=5
如果第一个字符为0,那么b+c一定等于a,反之b+c+1=a,因为它少一个01子串,构不成等号了,需要加一
code
int ask(string s){cout << 1 << " " << s << endl;int res;cin >> res;return res;
}
void solve(){int n;cin >> n;int a=ask("11");int b=ask("01");int c=ask("1");if(a+b==c) cout << "0 1 0" << endl;else cout << "0 1 1" << endl;int x;cin >> x;return ;
}
B. Make It Equal
思路
将数组中所有元素变为相同的一个数字,很显然我们会想到二分
为什么呢,例如:
如果我们将一个序列全部变为3,假设这个序列长度为4,则
序列最终为 3 3 3 3
那么我们在对每个元素操作一次,它就会变为2 2 2 2
即在相同元素的序列操作n次,我们可以让所有元素全部减去一
因此它是具备单调性的
显然我们要让操作次数最少,就应该让这个数字尽可能大,因此二分求右边界
在check函数里面,对于一个数 a i a_i ai
- 如果 a i < = x a_i<=x ai<=x 不进行操作
- 如果 a i > x a_i>x ai>x 操作 ( a i + 1 ) / 2 ∗ 2 (a_i+1)/2*2 (ai+1)/2∗2 向上取整
如果只操作一次,显然可能仍会有 a i > x a_i>x ai>x 的情况,所以需要循环多次
由于每次变化,数组中整体的值减一,因此可以用sum统计数组中所有的值
如果无解,输出 − 1 -1 −1
有解,输出 s u m − r ∗ n sum-r*n sum−r∗n
code
const int N=1e6+5;
int a[N],b[N],n;
bool check(int x){for(int i=1;i<=n;++i){b[i]=a[i]-x;}while(1){int flag=1;for(int i=1;i<=n;++i){if(b[i]>0){flag=0;b[i%n+1]+=(b[i]+1)/2;b[i]-=(b[i]+1)/2*2;}}if(flag) break;}for(int i=1;i<=n;++i){if(b[i]!=0) return false;}return true;
}
void solve(){cin >> n;int sum=0;for(int i=1;i<=n;++i){cin >> a[i];sum+=a[i];} int l=0,r=1e9+1,flag=1;while(l<r){int mid=l+r+1>>1;if(check(mid)) l=mid,flag=0;else r=mid-1;}cout << (flag?-1 : sum-r*n) << endl;return ;
}