A. Rook
模拟
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
string s;
cin>>t;
while(t--)
{
cin>>s;
for(int i=0;i<8;i++)
if(i!=s[0]-'a')
{
char c=i+'a';
cout<<c<<s[1]<<'\n';
}
for(int i=1;i<=8;i++)
if(i!=s[1]-'0')
{
char c=i+'0';
cout<<s[0]<<c<<'\n';
}
}
}
B. YetnotherrokenKeoard
用栈搞一搞
#include<bits/stdc++.h>
using namespace std;
struct node{
char c;
int idx;
};
bool cmp(node A,node B)
{
return A.idx<B.idx;
}
int main()
{
int t;
string s;
stack<node>a,b;
vector<node>v;
cin>>t;
while(t--)
{
v.clear();
cin>>s;
int n=s.length();
for(int i=0;i<n;i++)
{
if(s[i]=='B')
{
if(a.size()) a.pop();
}
else if(s[i]=='b')
{
if(b.size()) b.pop();
}
else
{
if(s[i]>='A'&&s[i]<='Z') a.push({s[i],i});
else b.push({s[i],i});
}
}
while(a.size()) v.push_back(a.top()),a.pop();
while(b.size()) v.push_back(b.top()),b.pop();
sort(v.begin(),v.end(),cmp);
for(int i=0;i<v.size();i++) cout<<v[i].c;
cout<<'\n';
}
}
C. Removal of Unattractive Pairs
每次挑出现次数最多的两个数抵消,用优先队列搞
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t,n;
string s;
priority_queue<int>q;
map<char,int>mp;
cin>>t;
while(t--)
{
mp.clear();
while(q.size()) q.pop();
cin>>n;
cin>>s;
int maxx=0;
for(int i=0;i<n;i++) mp[s[i]]++;
for(char i='a';i<='z';i++)
if(mp[i]) q.push(mp[i]);
while(q.size()>1)
{
int x=q.top();
q.pop();
int y=q.top();
q.pop();
if(x>1) q.push(x-1);
if(y>1) q.push(y-1);
}
if(!q.size()) cout<<"0\n";
else cout<<q.top()<<'\n';
}
}
D. Jumping Through Segments
二分答案,check一下每次可能跑到的最大区间范围。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll t,n,a[200010],b[200010];
bool check(ll mid)
{
ll x=0,y=0;
for(int i=1;i<=n;i++)
{
x-=mid,y+=mid;
if(x>b[i]||y<a[i]) return false;
x=max(x,a[i]),y=min(y,b[i]);
}
return true;
}
int main()
{
cin>>t;
while(t--)
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
ll l=0,r=1e18,mid,ans;
while(l<=r)
{
mid=(l+r)/2;
if(check(mid)) r=mid-1;
else l=mid+1;
}
cout<<l<<endl;
}
}
E. Good Triples
首先不能产生进位,否则进位一次之后数位等式左侧直接就会出现用一个10来做进位,补救的唯一办法就是等式右侧出现一个数位为10,然而数位只能是0~9,这是不可能的。
在不能进位的前提下,一旦数位和相等,那么数值和也一定相等。写一个竖式就很明显了。这样,我们就可以对每一位分开讨论。
对于n某一位上的数x,三元组在这一位上的和也为x,那么a在这一位可取的值为[0,x],则b与c在该位的和的范围也为[0,x]。容易发现,对于一个数y,存在y+1个二元组数值和为y。那么,存在三元组和为x的个数为
将每一位的结果相乘即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
ll t,n;
cin>>t;
while(t--)
{
cin>>n;
ll ans=1;
while(n)
{
ll x=n%10;
ans*=(x+1)*(x+2)/2;
n/=10;
}
cout<<ans<<'\n';
}
}
F. Shift and Reverse
和上次的div3类似,不过这次可以翻转,先把数组当成环首尾相连。两种操作都不会更改数组相邻位置的大小关系,因此,在环中必须存在一个长度至少为n的连续递增/递减子数组,否则不可行。
然后就是操作方案的问题了,如果是两段递增的数组,可以直接将后一段移到前一段,也可以翻转——移动后段——翻转;如果是两段递减的数组,可以是移动后段——翻转,或者翻转——移动后段。四种方案取min,注意移动时判断a[1]与a[n]的大小关系。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t,n,a[200010];
cin>>t;
while(t--)
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],a[i+n]=a[i];
int len1=0,len2=0,len;
a[2*n+1]=0;
for(int i=1;i<=2*n;i++)
for(int j=i+1;j<=2*n+1;j++)
if(a[j]<a[j-1])
{
len1=max(len1,j-i);
i=j-1;
break;
}
a[2*n+1]=1e9+10;
for(int i=1;i<=2*n;i++)
for(int j=i+1;j<=2*n+1;j++)
if(a[j]>a[j-1])
{
len2=max(len2,j-i);
i=j-1;
break;
}
len=max(len1,len2);
if(len<n)
{
cout<<"-1\n";
continue;
}
int flag=1;
for(int i=2;i<=n;i++)
if(a[i]<a[i-1])
{
flag=0;
break;
}
if(flag)
{
cout<<"0\n";
continue;
}
flag=1;
for(int i=2;i<=n;i++)
if(a[i]>a[i-1])
{
flag=0;
break;
}
if(flag)
{
cout<<"1\n";
continue;
}
int x=0,y=0,ans1=1e9,ans2=1e9,ans;
a[n+1]=1e9+10;
for(int i=2;i<=n;i++)
if(a[i]>a[i-1])
{
x=i-1;
break;
}
for(int i=x+2;i<=n+1;i++)
if(a[i]>a[i-1])
{
y=i-1;
break;
}
//cout<<x<<" "<<y<<endl;
if(y==n&&a[1]<=a[n]) ans1=min(x+1,y-x+1);
a[n+1]=0,x=0,y=0;
for(int i=2;i<=n;i++)
if(a[i]<a[i-1])
{
x=i-1;
break;
}
for(int i=x+2;i<=n+1;i++)
if(a[i]<a[i-1])
{
y=i-1;
break;
}
//cout<<x<<" "<<y<<endl;
if(y==n&&a[1]>=a[n]) ans2=min(x+2,y-x);
//cout<<ans1<<" "<<ans2<<endl;
ans=min(ans1,ans2);
cout<<ans<<'\n';
}
}