比賽連結
A. Verify Password
挨個判斷即可,秒了。
#include<cstdio>
#include<cstring>
using namespace std;
const int N=25;
int T,n;
char str[N];
bool is_digit(char ch){return ch>='0'&&ch<='9';}
bool is_lowercase(char ch){return ch>='a'&&ch<='z';}
bool check()
{
for(int i=1;i<n;i++)
{
if(is_lowercase(str[i])&&is_digit(str[i+1])) return false;
if(is_lowercase(str[i])&&is_lowercase(str[i+1]) && str[i]>str[i+1]) return false;
if(is_digit(str[i])&&is_digit(str[i+1]) && str[i]>str[i+1]) return false;
}
return true;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%s",&n,str+1);
printf("%s\n",check()?"YES":"NO");
}
}
B. Increase/Decrease/Copy
因為 \(b\) 的長度只比 \(a\) 的長度大一,所以一定只會複製一次,分以下兩種情況討論:
- 在將 \(a_i\) 化為 \(b_i\) 的過程中經過了 \(b_{n+1}\),此時只需要額外消耗複製的一次操作次數即可。
- 沒有經過,這時需要找離 \(b_{n+1}\) 最近的來化成它,而這個值只可能是其中一個 \(a_i\) 或 \(b_i\)
對於第二種情況,剛開始做的時候我只記錄了全域性最大最小值,沒有考慮到 \([1,2],[4,5]\) 要變成 \(3\) 這類情況並不是用全域性最大最小值來計算,而是以單組最大最小值來計算,所幸很快就改對了。
#include<cstdio>
#include<cmath>
#include<algorithm>
#define int long long
using namespace std;
const int N=1e6+5;
int T,n,a[N],b[N];
signed main()
{
scanf("%lld",&T);
while(T--)
{
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n+1;i++) scanf("%lld",&b[i]);
long long ans=0;
bool in_range=false;
for(int i=1;i<=n;i++)
{
int x=a[i],y=b[i];
if(x>y) swap(x,y); //make x<=y
ans+=y-x;
if(x<=b[n+1]&&b[n+1]<=y)
in_range=true;
}
ans++;
if(!in_range)
{
int add=0x3f3f3f3f;
for(int i=1;i<=n;i++)
{
int x=a[i],y=b[i];
if(x>y) swap(x,y); //make x<=y
if(b[n+1]<x) add=min(add,x-b[n+1]);
if(b[n+1]>y) add=min(add,b[n+1]-y);
}
ans+=add;
}
printf("%lld\n",ans);
}
return 0;
}
C. Job Interview
這道題做的還算順,就是沒開 long long
坑了我好一會,下次要開 long long
的地方一定要第一時間開上,不要想著後面在一個一個改。
在洛谷上發了一篇題解:點選這裡。
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=2e5+5;
int T,n,m;
int prog[N],test[N];
long long sum_prog[N],sum_test[N],sum_ok[N];
int cnt_prog[N],cnt_test[N];
//以上變數含義見題解內容
//prog(rammer)程式設計師;test(er)測試員
long long getsum(long long sum[],int l,int r)
{
return sum[r]-sum[l-1];
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n+m+1;i++)
{
scanf("%d",&prog[i]);
sum_prog[i]=sum_prog[i-1]+prog[i];
}
for(int i=1;i<=n+m+1;i++)
{
scanf("%d",&test[i]);
sum_test[i]=sum_test[i-1]+test[i];
}
for(int i=1;i<=n+m+1;i++)
{
cnt_prog[i]=cnt_prog[i-1];
cnt_test[i]=cnt_test[i-1];
if(prog[i]>test[i]) //這個候選人是預備程式設計師
{
cnt_prog[i]++;
sum_ok[i]=sum_ok[i-1]+prog[i];
}
if(prog[i]<test[i]) //這個候選人是預備測試員
{
cnt_test[i]++;
sum_ok[i]=sum_ok[i-1]+test[i];
}
}
for(int pos=1;pos<=n+m+1;pos++)
{
int l=0,r=n+m+1+1;
while(l+1<r) //[1,l] ok; [r,n+m+1] exceeded
{
int mid=l+r>>1,prog_now=cnt_prog[mid]; //當前位置以前的預備程式設計師人數
if(prog[pos]>test[pos] && pos<=mid) prog_now--; //排除當前候選人
if(prog_now<=n) l=mid;
else r=mid;
}
int pos_prog=l;
l=0,r=n+m+1+1;
while(l+1<r) //[1,l] ok; [r,n+m+1] exceeded
{
int mid=l+r>>1,test_now=cnt_test[mid]; //當前位置以前的預備測試員人數
if(prog[pos]<test[pos] && pos<=mid) test_now--; //排除當前候選人
if(test_now<=m) l=mid;
else r=mid;
}
int pos_test=l;
long long ans=0;
if(pos_prog<pos_test) //程式設計師先滿員,以後所有人只能當測試員
{
ans=getsum(sum_ok,1,pos_prog)+getsum(sum_test,pos_prog+1,n+m+1);
if(pos<=pos_prog) ans-=max(prog[pos],test[pos]); //排除當前候選人
else ans-=test[pos];
}
else if(pos_prog>pos_test) //測試員先滿員,以後所有人只能當程式設計師
{
ans=getsum(sum_ok,1,pos_test)+getsum(sum_prog,pos_test+1,n+m+1);
if(pos<=pos_test) ans-=max(prog[pos],test[pos]); //排除當前候選人
else ans-=prog[pos];
}
else
{
if(pos_prog==n+m+1) //程式設計師和測試員數量剛好夠
{
ans=getsum(sum_ok,1,n+m+1);
ans-=max(prog[pos],test[pos]);
}
else return -1; //為了防止出現意想不到的情況
//上面的 if/else 語句可以刪去,只保留中間的處理部分
}
printf("%lld ",ans);
}
putchar('\n');
}
return 0;
}
D. Invertible Bracket Sequences
賽事沒做起,賽後補的。
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+5,LogN=20;
int T,n;
char str[N];
int sum[N];
vector<int> pos[N];
long long ans=0;
namespace ST_Table{
int f[N][LogN];
int lg2[N];
void Init(int arr[])
{
for(int i=2;i<=n;i++)
lg2[i]=lg2[i>>1]+1;
for(int i=1;i<=n;i++)
f[i][0]=arr[i];
for(int k=1;k<=lg2[n];k++)
for(int i=1;i+(1<<k-1)-1<=n;i++)
f[i][k]=max(f[i][k-1],f[i+(1<<k-1)][k-1]); //[i,i+2^(k-1)-1]|[i+2^(k-1)][i+2^k-1]
return;
}
int query(int l,int r)
{
int p=lg2[r-l+1];
return max(f[l][p],f[r-(1<<p)+1][p]); //[l,l+2^p-1]|[r-2^p+1,r]
}
} //namespace ST_Table
void ClearData()
{
for(int i=1;i<=n;i++)
pos[i].clear();
ans=0;
return;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%s",str+1);
n=strlen(str+1);
for(int i=1;i<=n;i++)
{
if(str[i]=='(') sum[i]=sum[i-1]+1;
if(str[i]==')') sum[i]=sum[i-1]-1;
pos[sum[i]].push_back(i);
}
ST_Table::Init(sum);
for(int left=1;left<=n;left++)
{
int l=left-1,r=n+1;
while(l+1<r)
{
int mid=l+r>>1;
if(ST_Table::query(left,mid)<=sum[left-1]<<1) l=mid;
else r=mid;
}
int right=l;
vector<int> &vp=pos[sum[left-1]];
ans+=
(upper_bound(vp.begin(),vp.end(),right)-1) //last <=
-(lower_bound(vp.begin(),vp.end(),left)) //first >=
+1;
}
printf("%lld\n",ans);
ClearData();
}
return 0;
}