A. 画像
シミュレーション
#include<bits/stdc++.h>
using namespace std;
map<int,int>mp;
int main()
{
int T;cin>>T;
while(T--){
mp.clear();char a,b,c,d;cin>>a>>b>>c>>d;
mp[a]++;mp[b]++;mp[c]++;mp[d]++;
int sum=0;int r=4;
for (auto i:mp){
if(i.second==1&&r!=1){sum++;r--;}
if(i.second==2&&r!=2){sum++;r-=2;}
}
cout<<sum<<endl;
}
return 0;
}
問題の解決は set で行われます。これはより簡単です。
#include<bits/stdc++.h>
using namespace std;
set<char>mp;
int main()
{
int T;cin>>T;
while(T--){
mp.clear();
char a,b,c,d;cin>>a>>b>>c>>d;
mp.insert(a);mp.insert(b);mp.insert(c);mp.insert(d);
cout<<(int)mp.size()-1<<endl;
}
return 0;
}
B. デッドリーレーザー
アイデア: まず、どのように進むにしても、最小歩数は n+m-2 であるため、道路を遮るレーザーがカバーする範囲によって決まります。
ブロック方法は4つあります
1. 左下隅をブロック 2. 右上隅をブロック 3. 垂直方向をブロック 4. 水平方向をブロック
コード:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int T;cin>>T;
while(T--){
int n,m,sx,sy,d;cin>>n>>m>>sx>>sy>>d;
if(m-sy<=d&&n-sx<=d||sy-1<=d&&sx-1<=d||sy-1<=d&&m-sy<=d||sx-1<=d&&n-sx<=d)
cout<<-1<<'\n';
else cout<<(n+m-2)<<'\n';
}
return 0;
}
C. Min-Max 配列の変換
注: データ範囲は 2e5 で、小さすぎる場合、配列は TLE になります。
アイデア:
まず、最小の配列を見つけるのは簡単です。それに正確に等しい数値を見つけるだけです。
最大の数を見つけるには、サンプルの規則を見てください。n-1 から 0 まで、a[i] が b[i-1] より大きい場合、b[i-1] は a[i にはなり得ないことを意味します] とその前 数値の合計なので、新しい始まりとして b[i-1] から開始します。それ以外の場合は、前の b[i] が a[i] より大きいため、制限がないため、最大のものを選択できます
#include<bits/stdc++.h>
using namespace std;
int a[200005],b[200005],d[200005];
int main()
{
ios::sync_with_stdio(0);
int T;cin>>T;
while(T--){
int n;cin>>n;
int minn=999999999;int maxx=0;
for(int i=0;i<n;i++)cin>>a[i];for(int i=0;i<n;i++)cin>>b[i];
int l=0;
for(int i=0;i<n;i++){while(b[l]<a[i])l++;cout<<b[l]-a[i]<<" ";}
cout<<'\n';
l=n-1;
for(int i=n-1;i>=0;i--){d[i]=b[l]-a[i];if(a[i]>b[i-1])l=i-1;}
for(int i=0;i<n;i++)cout<<d[i]<<" ";cout<<'\n';
}
return 0;
}
真実を見つけるのは前から後ろまでほとんど同じです
#include<bits/stdc++.h>
using namespace std;
int a[200005],b[200005];
int main()
{
ios::sync_with_stdio(0);cin.tie(0);
int T;cin>>T;
while(T--){
int n;cin>>n;
for(int i=0;i<n;i++)cin>>a[i];
for(int i=0;i<n;i++)cin>>b[i];
int l=0;
for(int i=0;i<n;i++){while(b[l]<a[i])l++;cout<<b[l]-a[i]<<" ";}
cout<<'\n';l=0;
for(int i=0;i<n;i++){
l=max(l,i);while(a[l+1]<=b[l]&&l+1<n)l++;cout<<b[l]-a[i]<<" ";
}
cout<<'\n';
}
return 0;
}
D. 最大 AND
タイトル: 配列 a と b があり、配列 c は a と b の XOR 演算によって取得され、最終的な値は配列 c の AND 演算であり、最大値を見つけます
アイデア:
方法 1:
最後の値の最上位ビットは、各 c 配列の 1 の位置でなければならないことがわかっています。
1 の各位置は、配列 a の 1 と配列 b の 0 (または配列 a の 0 と配列 b の 0) で構成されます。
次に、上記の数値 x、x、および各 a[i] を設定できます。結果 cc は、x に 1 桁があり、a[i] に同時に 1 桁がある場合にのみ表示されます。
x と上記のそれぞれ (反転 b[i]) の結果 dd は、x に 1 を含む数字と同時に 1 を含む数字(反転 b[i])のみを表示できることになります。
cc と dd が 1 対 1 に等しい場合、a[i] の 1 と b[i] の 0 は 1 対 1 に対応できることを意味します (また、 a[i] の 0 と b[i] の 1)
したがって、チェックするときは、cc と dd が等しいかどうかを判断するだけで済みます。
コード:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[100005];int b[100005];int n;
int c[100005];int d[100005];
bool check(int x){
for(int i=1;i<=n;i++)c[i]=a[i]&x;
for(int i=1;i<=n;i++)d[i]=(~b[i])&x;
sort(c+1,c+1+n);sort(d+1,d+1+n);
for(int i=1;i<=n;i++){
if(c[i]!=d[i])return 0;
}
return 1;
}
signed main()
{
int T;cin>>T;
while(T--){
int coun=0;cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
int res=0;
for(int i=31;i>=0;i--){
if(check(res|(1<<i)))res=res|((1<<i));
}
cout<<res<<'\n';
}
return 0;
}
方法 2 (および検索)
特定のビットの 1 の部分が b の 0 の部分とペアになっている場合、数値が間違っている場合は続行します
正しい場合は、a の 1 の部分と、その部分の b の 0 の部分を一致させます。数値が間違っている場合は、続行します。
でもまだ見てないんですが…