A. Sweet Problem
A题是我写的最纠结的,换了四五种做法。。
#include<bits/stdc++.h>
using namespace std;
const int N=10;
int a[N];
int n;
int main()
{
int _;cin>>_;while(_--)
{
n=3;
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
sort(a+1,a+1+n);
int d=a[3]-a[2];
a[3]-=d;
int ans=a[2];
int mi=min(d,a[1]);
a[1]-=mi;
ans+=mi;
if(a[1]){
if(a[1]%2) a[1]--;
mi=min(a[1]/2,a[2]);
if(mi>=0) ans+=mi;
}
printf("%d\n",ans);
}
}
B. PIN Codes
由于n<=10,只改变某一位即可
注意输出占4位
#include<bits/stdc++.h>
using namespace std;
const int N=20;
int a[N],b[N];
int n;
int main()
{
int _;cin>>_;while(_--)
{
scanf("%d",&n);
memset(b,0,sizeof(b));
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
}
map<int,int>mp;
mp[a[1]]=1;
int ans=0;
for(int i=2;i<=n;++i){
if(mp[a[i]]==1){
b[i]=1;
}
mp[a[i]]=1;
}
for(int i=1;i<=n;++i){
if(b[i]==0) continue;
int x=a[i];
int d=x%10;
while(mp[x]==1){
d=(d+1)%10;
x=a[i]/10*10+d;
}
a[i]=x;
mp[a[i]]=1;
ans++;
}
printf("%d\n",ans);
for(int i=1;i<=n;++i) printf("%04d\n",a[i]);
}
}
C. Everyone is a Winner!
C不就是一眼分块做法,3分钟A
#include<bits/stdc++.h>
using namespace std;
int main()
{
int _;cin>>_;while(_--)
{
int n;scanf("%d",&n);
vector<int>ans;
int d=1;
for(int l=1,r;l<=n;l=r+1){
int x=n/l;
r=n/(n/l);
//printf("l:%d r:%d\n",l,r);
ans.push_back(x);
}
ans.push_back(0);
sort(ans.begin(),ans.end());
printf("%d\n",ans.size());
for(int v:ans){
printf("%d ",v);
}
puts("");
}
}
D. Secret Passwords
D一眼并查集维护联通块,10分钟A,
#include<bits/stdc++.h>
using namespace std;
const int N=30,M=100;
int fa[N],vis[N];
int n;
char s[M];
int getid(char c){
return c-'a'+1;
}
int find(int x)
{
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%s",s+1);
int len=strlen(s+1);
for(int i=1;i<=len;++i){
if(fa[getid(s[i])]==0){
fa[getid(s[i])]=getid(s[i]);
}
}
for(int i=1;i<=len;++i){
if(i+1<=len){
int f1=find(fa[getid(s[i])]);
int f2=find(fa[getid(s[i+1])]);
if(f1!=f2){
fa[f2]=f1;
}
}
}
}
int ans=0;
for(int i=1;i<=26;++i){
int id=find(i);
if(id!=0&&vis[id]==0){
ans++;
vis[id]=1;
}
}
printf("%d\n",ans);
}
E. Editor
E题就是一个动态维护括号配对,(赋值1,,)赋值-1
维护前缀和,和前缀和最小值就可以得到括号是否匹配。。
维护前缀和最大值就可以得到最大的嵌套括号
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
/*
sum 维护的是左右括号的个数 为零的时候说明 左右括号数量相等
mi值维护的是最小值,最小值越小,那么连续的未匹配的右括号越多))))当mi[1]!=0 那么就是不匹配的
因为又剩余的))
mx值维护的是最大值,最大值越大,那么连续的未匹配的左括号越多((((,
当整个括号序列是匹配的,那么mx[1]就是维护的答案( 嵌套的最大括号)
*/
int sum[maxn<<2],mi[maxn<<2],ma[maxn<<2],n;
char s[maxn];
void update(int o,int l,int r,int pos,int c)
{
if(l==r)
{
sum[o]=c;mi[o]=c;ma[o]=c;
return ;
}
int m=(l+r)>>1;
if(pos<=m) update(o<<1,l,m,pos,c);
else update(o<<1|1,m+1,r,pos,c);
sum[o]=sum[o<<1]+sum[o<<1|1];
//很妙的更新方程:类似于动态更新前缀和
//我一直以为认为前缀和无法用线段树动态更新,现在这个方程证明了是可以的
ma[o]=max(ma[o<<1],sum[o<<1]+ma[o<<1|1]);
mi[o]=min(mi[o<<1],sum[o<<1]+mi[o<<1|1]);
}
int main()
{
scanf("%d",&n);
scanf("%s",s);
int x=1;
for (int i=0;i<n;i++)
{
if(s[i]=='L') {if(x>1)--x;}
else if(s[i]=='R') ++x;
else if(s[i]=='(') update(1,1,n,x,1);
else if(s[i]==')') update(1,1,n,x,-1);
else update(1,1,n,x,0);
if (mi[1]!=0 ||sum[1]!=0) printf("-1 ");
else printf("%d ",ma[1]);
}
return 0;
}