A
#include <bits/stdc++.h>
using namespace std;
void solve(){
int n;
cin>>n;
if(n%3==0){
cout<<n/3-1+1<<" "<<n/3-1+2<<" "<<n/3-1<<endl;
}
else if(n%3==1){
cout<<n/3-1+1<<" "<<n/3-1+3<<" "<<n/3-1<<endl;
}
else
cout<<n/3-1+2<<" "<<n/3-1+3<<" "<<n/3-1<<endl;
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
system("pause");
}
B
两个数组做差,然后比较非零的所有位上数字是否相同。
#include <bits/stdc++.h>
using namespace std;
int solve(){
int n;
cin>>n;
vector<int>a(n),b(n);
for( int i=0;i<n;i++){
cin>>a[i];
}
for( int i=0;i<n;i++){
cin>>b[i];
}
for( int i=0;i<n;i++){
a[i]-=b[i];
if(a[i]<0) return false;
}
int dec=*max_element(a.begin(),a.end());
for( int i=0;i<n;i++){
if(b[i]==0) continue;
if(a[i]!=dec) return false;
}
return true;
}
int main(){
int t;
cin>>t;
while(t--){
if(solve())
cout<<"YES"<<"\n";
else
cout<<"NO"<<"\n";
}
system("pause");
}
C
直接模拟即可
#include <bits/stdc++.h>
using namespace std;
void solve(){
int n;
cin>>n;
vector<int>s(n),f(n);
for( int i=0;i<n;i++) cin>>s[i];
for( int i=0;i<n;i++) cin>>f[i];
int cur=0;
for( int i=0;i<n;i++){
if(s[i]>=cur) cur=s[i];
cout<<f[i]-cur<<" ";
cur=f[i];
}
cout<<"\n";
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
system("pause");
}
D
使用类似双指针,维护一个区间内W的个数
#include <bits/stdc++.h>
using namespace std;
int solve(){
int n,k;
cin>>n>>k;
string s;
cin>>s;
int tot=0;
for( int i=0;i<k;i++){
if(s[i]=='W') tot++;
}
int ans=tot;
for( int i=k;i<n;i++){
if(s[i]=='W') tot++;
if(s[i-k]=='W') tot--;
ans=min(ans,tot);
}
return ans;
}
int main(){
int t;
cin>>t;
while(t--){
cout<<solve()<<"\n";
}
system("pause");
}
E
本题的思路是,如何让整除之后的损失最小。
首先,为了简化问题,可以将所有的数对k取模。
从大到小遍历所有处理完的数
对于某个数x,显然,x与k-x配对损失最小。如果没有k-x,那么就选取比k-x大的最小的数。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll solve(){
int n,k;
cin>>n>>k;
vector<int>v(n);
for( int i=0;i<n;i++) cin>>v[i];
ll ans=0;
for( int i=0;i<n;i++){
ans+=v[i]/k;
v[i]%=k;
}
multiset<int>se;
for( int i=0;i<n;i++) se.insert(v[i]);
while(!se.empty()){
int x=*--se.end();
se.erase(--se.end());
auto it=se.lower_bound(k-x);
if(it!=se.end()){
se.erase(it);
ans++;
}
else{
break;
}
}
return ans;
}
int main(){
int t;
cin>>t;
while(t--){
cout<<solve()<<"\n";
}
system("pause");
}
F
排列问题可以抽象成环来考虑。
若在位置i上的数为x,那么,我们可以认为点i和点x之间连上了一条边。
通过上述处理,最终我们可以得到一个由若干个环组成的图。
显然,若某一个环的长度为y,那么这些数字通过轮换回到初始状态的时间为y的倍数。
一个图中有若干个环,我们只需要计算这些环的长度的最小公倍数即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll lcm( ll x,ll y){
return x*y/__gcd(x,y);
}
ll solve(){
int n;
cin>>n;
string s;
cin>>s;
vector<int>v(n);
for( int i=0;i<n;i++){
cin>>v[i];
v[i]--;
}
ll ans=1;
vector<int>vis(n);
for( int i=0;i<n;i++){
if(vis[i]) continue;
int cur=i;
string ss,ns;
while(vis[cur]==0){
ss.push_back(s[cur]);
vis[cur]=1;
cur=v[cur];
}
ns=ss;
int cnt=0;
while(1){
rotate(ns.begin(),ns.begin()+1,ns.end());
cnt++;
if(ns==ss) break;
}
ans=lcm(cnt,ans);
}
return ans;
}
int main(){
int t;
cin>>t;
while(t--){
cout<<solve()<<"\n";
}
system("pause");
}
G
本题需要用到一个知识点,就是使用map来维护区间问题。
使用map维护的方法是,键值key存储左端点,数值val存储右端点和区间的值。
map维护区间的数据结构,支持区间合并和区间分裂,一次合并和一次分裂的时间复杂度均为logn
对于本题来说,一次减速操作会产生一个新的train(区间),或将若干个train(区间)合并。
由于开始至多有n个区间,n次操作至多产生n个区间,合并的时间复杂度至多为nlogn,分裂的时间复杂度至多也为nlogn
#include<bits/stdc++.h>
// #pragma GCC optimize(2)
using namespace std;
typedef long long ll;
void solve(){
int n,m;
cin>>n>>m;
vector<int>v(n+1);
for( int i=1;i<=n;i++){
cin>>v[i];
}
map<int,pair<int,int>>mp;
mp[1]={1,v[1]};
for( int i=2;i<=n;i++){
auto it=*--mp.end();
int x=it.first,y=it.second.first,speed=it.second.second;
if(v[i]>=speed) {
mp[x]={y+1,speed};
}
else {
mp[i]={i,v[i]};
}
}
vector<int>ans;
while(m--){
int k,d;
cin>>k>>d;
auto it=prev(mp.upper_bound(k));
v[k]-=d;
if(v[k]>=it->second.second) {
ans.push_back(mp.size());
continue;
}
else
{
if(k==it->first){
it->second.second=v[k];
}
else{
mp[k]={it->second.first,v[k]};
it->second.first=k-1;
}
auto cur=mp.find(k);
while(next(cur)!=mp.end()&&next(cur)->second.second>=v[k]){
cur->second.first=next(cur)->second.first;
mp.erase(next(cur));
}
}
ans.push_back(mp.size());
}
for( auto it:ans){
cout<<it<<" ";
}
cout<<"\n";
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
system("pause");
}