A. Prof. Slim
题意:给出一个数组,每次操作可以选择两个下标i,j,如果a[i]*a[j]<0,那么可以将它们替换成自己的相反数。注意:a[i]!=0。问操作若干次后是否能让数组是不下降序列。
思路:在正数前面的负数一定要交换符号,交换完了以后check一遍即可。
AC code:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+10;
int n,a[N],b[N];
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i];
}
int pos1=-1,pos2=-1,cnt1=0,cnt2=0;
for(int i=1;i<=n;i++){
if(a[i]<0){
cnt2++;
}else{
cnt1++;
}
}
if(cnt1==0 || cnt2==0){
for(int i=1;i<n;i++){
if(a[i]>a[i+1]){
cout<<"NO"<<endl;
return ;
}
}
}
int cnt=min(cnt1,cnt2);
for(int i=1;i<=n;i++){
if(a[i]>0){
pos1=i;
break;
}
}
for(int i=n;i>=1;i--){
if(a[i]<0){
pos2=i;
break;
}
}
while(pos1<pos2 && cnt>=0){
b[pos1]=-b[pos1];
b[pos2]=-b[pos2];
cnt--;
int t1=pos1;
int t2=pos2;
for(int i=pos1+1;i<=n;i++){
if(a[i]>0){
pos1=i;
break;
}
}
if(t1==pos1) break;
for(int i=pos2-1;i>=1;i--){
if(a[i]<0){
pos2=i;
break;
}
}
if(t2==pos2) break;
}
// for(int i=1;i<=n;i++) cout<<b[i]<<' ';
// cout<<endl;
for(int i=1;i<n;i++){
if(b[i]>b[i+1]){
cout<<"NO"<<endl;
return;
}
}
cout<<"YES"<<endl;
}
int main(){
ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
B. Dorms War
题意:给出一个字符串以及一些特殊的字母,如果字符串中某个字母的下一个字母是特殊字母,那么该字母将会被删掉,次数+1。如果特殊字母前面没有其他字母了,那就结束了,输出次数。
思路:观察样例就可以发现,两个相邻的特殊字母的最大距离就是答案,除此之外还有一种可能是从字符串第一个字母到第一个特殊字母的距离要与最大距离相比较,因为如果最大距离还要小于第一个字母到第一个特殊字母的距离的话,那么删除了最大距离的次数之后还有剩余字母可以继续删除。
AC code:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n,k,vis[30];
string s;
void solve(){
cin>>n>>s;
s='!'+s;
cin>>k;
for(int i=0;i<=26;i++) vis[i]=0;
for(int i=1;i<=k;i++){
char c;
cin>>c;
vis[c-'a']=1;
}
int cnt=0;
for(int i=1;i<=n;i++){
if(vis[s[i]-'a']){
cnt++;
}
}
if(cnt==1){
int t=0;
for(int i=1;i<=n;i++){
if(vis[s[i]-'a']){
cout<<t<<endl;
return;
}else{
t++;
}
}
}else if(cnt==0){
cout<<0<<endl;
return ;
}
int t=0;
bool ok=0;
int ans=0;
for(int i=1;i<=n;i++){
if(vis[s[i]-'a'] && !ok){
ok=1;
}else if(vis[s[i]-'a'] && ok){
ans=max(ans,t);
t=0;
ok=1;
}else if(vis[s[i]-'a']==0 && ok){
t++;
}
}
cnt=0;
for(int i=1;i<=n;i++){
if(vis[s[i]-'a']){
break;
}else{
cnt++;
}
}
if(cnt>ans){
cout<<cnt<<endl;
}else{
cout<<ans+1<<endl;
}
}
int main(){
ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
C. Where is the Pizza?
题意:给出排列a和排列b和不完整的排列c,排列c只给了一部分数,对于没给的数,可以选择c[i]=b[i] or c[i]=a[i],问有多少种方案,对1e9取模。
思路:首先假设c【i】全部都是未知数,全部的数都需要从a或者b中获取,假设第一个数选了b[i],那么a[j]=b[i]的下标j也只能再选b[j],即确定选了一个数,那么后面要选的数也就都确定了。如果能够构成一个环,那么对答案的贡献就是乘积因子2,具体看代码模拟一下就懂了。
AC code:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10;
const int mod=1e9+7;
int n,a[N],b[N],c[N],vis[N],mp[N];
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
mp[a[i]]=i;
vis[i]=0;
}
for(int i=1;i<=n;i++) cin>>b[i];
for(int i=1;i<=n;i++) cin>>c[i];
int ans=1;
for(int i=1;i<=n;i++){
if(vis[a[i]]) continue;
int j=i;
bool ok=1;
if(c[i]) ok=0;
vis[a[i]]=1;
while(1){
j=mp[b[j]];
if(c[j]) ok=0;
vis[a[j]]=1;
if(a[i]==b[j]) break;
}
if(ok && (i!=j)) ans=2*ans%mod;
}
cout<<ans<<endl;
}
int main(){
ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}