目录
A. Vlad and the Best of Five
B. Vlad and Shapes
C. Vlad and a Sum of Sum of Digits
D. Vlad and Division
E. Vlad and an Odd Ordering
F. Vlad and Avoiding X
G. Vlad and Trouble at MIT
A. Vlad and the Best of Five
我们可以使用string中的count函数来查询数量
void solve(){
string a; cin>>a;
cout<<(count(a.begin(),a.end(),'A')>=3 ? 'A' : 'B')<<endl;
return ;
}
B. Vlad and Shapes
判断由1组合成的图形是正方形还是三角形,对于这两个图案我们发现正方形是有规律的可以考虑找到图中1的最远的四个角,如果是正方形的话里面就是都是满的也就是满足四个最大方位形成正方形的面积反之为三角形
void solve(){
cin>>n;
int ans=0;
int x1=n+1,x2=-1,y1=n+1,y2=-1;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
char x; cin>>x;
if(x=='1'){
ans++;
x1=min(x1,i);
x2=max(x2,i);
y1=min(y1,j);
y2=max(y2,j);
}
}
cout<<((y2-y1+1)*(x2-x1+1)== ans ? "SQUARE" : "TRIANGLE")<<endl;
return ;
}
C. Vlad and a Sum of Sum of Digits
我们观察和发现数据范围只有2e5也就是说我们可以直接使用预处理每一个数的方式来计算,每次查询就是o(1)的
int check(int x){
int res=0;
while(x){
res+=x%10;
x/=10;
}
return res;
}
void intn(){
for(int i=1;i<N;i++){
ans[i]=check(i)+ans[i-1];
}
}
void solve(){
cin>>n;
cout<<ans[n]<<endl;
return ;
}
D. Vlad and Division
我们来分组计算每一个个组中的两个数的二进制位互不相同,也就是说我们一个组中最多两个数
我们直接用map存起来然后判断是否有他的对应数出现即可,同时标记这个数是否被前面的数给使用组合了,找对应数使用位运算中的异或
LL p=(1ll<<31)-1;
void solve(){
cin>>n;
map<LL,int> mp,st;
for(int i=1;i<=n;i++){
LL x; cin>>x;
mp[x]++;
}
int res=0;
for(auto&[v,w]:mp){
if(st.count(v)) continue;
if(mp.count(p^v)){
res+=max(w,mp[p^v]);
st[p^v]++;
}
else res+=w;
}
cout<<res<<endl;
return ;
}
E. Vlad and an Odd Ordering
依照题目意思我们进行对20模拟,同时思考可以知道一开始我们删除了所有的奇数,奇数*奇数=奇数,那么接下来只有偶数的删除才会有用同时如果不是2的幂次的话其他偶数都是可以由奇数*偶数得到的也就是前面的偶数就已经判断过了,所以,只有2的幂次才有删除作用,接着对于2的幂次我们看有多少在其中中有一部分是偶数被前面的删除了,所以要除以2然后依次变化即可找到不可以变化的即可
void solve(){
cin>>n>>m;
if(2*m-1<=n){
cout<<2*m-1<<endl;
}
else{
m-=(n+1)/2;
for(LL i=2;i<=n;i*=2){
LL x = (n/i+1)/2;
if(m>x){
m-=x;
}
else{
LL ans= i * (2*m-1);
cout<<ans<<endl;
return ;
}
}
}
return ;
}
F. Vlad and Avoiding X
我们要的是删除一个x我们发现数据范围只有49同时肯定不会在边上也就是25,这个时候我们看是不是可以使用dfs,我们找一下有没有剪枝的性质,我们是从左上角开始的,也就是说对后面有影响的只有中间左下右下,同时使用最优性剪枝世家九年复杂度就ok了
void solve(){
n=7;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>s[i][j];
int ans=n*n;
int dx[]={0,1,1},dy[]={0,-1,1};
auto dfs = [&](auto dfs,int sum){
if(sum>ans) return ;
for(int i=2;i<n;i++)
for(int j=2;j<n;j++)
if(s[i][j]=='B' && s[i-1][j-1]=='B' && s[i-1][j+1]=='B' && s[i+1][j-1]=='B' && s[i+1][j+1]=='B' ){
for(int u=0;u<3;u++){
int x=i+dx[u],y=j+dy[u];
s[x][y]='W';
dfs(dfs,sum+1);
s[x][y]='B';
}
return ;
}
ans=sum;
return ;
};
dfs(dfs,0);
cout<<ans<<endl;
return ;
}
G. Vlad and Trouble at MIT
注意题目告诉我们这是一棵树所以我们要使用树上的知识来处理由小问题向上传递,考虑使用
0/1/2代替C/P/S,对于最后的节点如果我是C那么我要看我字节点的P,S的数量取其中最少的,那我如何向上传递呢? 假设cnt[1]>cnt[2]那么我先把2的处理我此时此刻的C中还有1没有处理完代表1,反之代表2,如果相等的话依旧代表0可以依照上面的情况来变化向谁建墙,由此向上回溯,如果是P/S就是明显的直接加上对方的即可
vector<int> g[N];
char s[N];
void solve(){
cin>>n;
for(int i=1;i<=n;i++) g[i].clear();
for(int i=2;i<=n;i++){
int x; cin>>x;
g[x].push_back(i);
g[i].push_back(x);
}
for(int i=1;i<=n;i++) cin>>s[i];
vector<int> dp(n+1);
int ans=0;
auto dfs = [&](auto dfs,int u,int fa){
vector<int> cnt(3);
if(g[u].size()==1 && u!=1){
if(s[u]=='P') dp[u]=1;
else if(s[u]=='S') dp[u]=2;
return ;
}
for(auto&v:g[u]){
if(v==fa) continue;
dfs(dfs,v,u);
cnt[dp[v]]++;
}
if(s[u]=='C'){
ans+=min(cnt[1],cnt[2]);
if(cnt[1]==cnt[2]){
dp[u]=0;
}
else if(cnt[1]>cnt[2]){
dp[u]=1;
}
else dp[u]=2;
}
else if(s[u]=='P'){
ans+=cnt[2];
dp[u]=1;
}
else{
ans+=cnt[1];
dp[u]=2;
}
};
dfs(dfs,1,-1);
cout<<ans<<endl;
return ;
}