2020.2.6試合の問題解
5246 ワード
T 1文字列脱重
この問題は言うまでもなく、どうでもいい.
本題の文字列はすでに順番に並んでいるので、この文字列と前の文字列が等しいかどうかを直接判断すればいい.
全部読み込んでC++が持つ(unique)関数でやり直すこともできます.
複雑度(O(Sigma len)).
スレッド:
T 2クロススター
この問題は難しくありません.私はまた一定の難易度を下げて、カードの精度がなくて、カードの常です.
この問題は2種類に分けて考慮して、傾きの積は-1に等しくて、あるいは平行と座標軸で、みんながどのように2点の直線の傾きを求めることを知っていると信じています.(i)番目の点の座標を((x_i,y_i))とすると、(i,j)番目の点を通過する直線の傾きが(frac{y_i-y_j}{x_i-x_i-x_j})となり、(y_i-y_j=0)の場合、その直線は(x)軸に平行であり、(x_i-x_j=0)の場合、その直線は(y)軸に平行である.
(500)個を超えない点しかないので、(frac{500times(500-1)}{2}=124750)を超えない直線しかありません.暴力が維持される場合、時間の複雑さは(O(n^4))である.
傾きを1つのデータ構造で維持することを考慮すると、(STL)のマッピングコンテナ(map)を使用して維持することは容易である.線分を1つ加えるたびに、増加した答えを統計します.
複雑度(O(Tn^2 log(n))
スレッド(1):
スレッド(2):
T 3迷宮の道を探す
この問題は主にみんなの広捜に対する理解を考察した.
前の(40)点に対して、直接深く探せばいい、(O(玄学)).
中間の(30)点については,広捜の古典的な例題であり,直接広捜,(O(nm))であることが容易にわかる.
すべてのデータについて、広捜を改良しようと試みた.広捜の思想は1つの優先キューを維持して、今距離の小さい位置を前に置いて、距離の大きい位置を後ろに置いて、本題の中でチームの頭とチームの尾の値の差は1を超えません.
現在、キューを取り出し、キューの距離を(dis)とし、トランスポートゲートを使用し、((i,j))位置に到達したと考えると、((i,j))の距離を(dis)に更新し、元のキューが最小であるため、直接キューに入れればよい.
さらに隣接する格子((i,j))まで歩くことを考慮して、距離は(dis+1)で、チームヘッドとチームテールの差は(1)より大きくないので、チームテールに入れればよい.
全複雑度(O(nm)).
スレッド:
T 4家計簿の整理
この問題はビット演算に関する分析を少し受けた.
(i&(i-1))が何を表しているのか考えてみましょう.(10)を例にしてみましょう.(10&9=8)つまり((1010)2\&(1001)_2=(1000)_2)、つまりバイナリの下の最下位を外したことに相当します.
現在は(i)の最後の位置を考え、現在は右から左へ数える(k)位を考えると、彼の父は(i-2^{k-1})である.私たちは(2^{k-1}|i)を知ることができて、しかも(2^kmid i)なので、せっかく(2^k|i-2^k)を得ることができなくて、それから(i-2^kin[l,r])を知っているので、直接除算で([l,r])の中の(2^k)の倍数を統計すればいいので、境界が取れるかどうかを分類して考えてください.
複雑度(O(Tlog(値域)approx O(50 T)).
スレッド:
完結散花QQQ
この問題は言うまでもなく、どうでもいい.
本題の文字列はすでに順番に並んでいるので、この文字列と前の文字列が等しいかどうかを直接判断すればいい.
全部読み込んでC++が持つ(unique)関数でやり直すこともできます.
複雑度(O(Sigma len)).
スレッド:
#include
using namespace std;
string s[100010];
int n;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) cin>>s[i];
n=unique(s+1,s+n+1)-s-1;
for(int i=1;i<=n;i++) cout<
T 2クロススター
この問題は難しくありません.私はまた一定の難易度を下げて、カードの精度がなくて、カードの常です.
この問題は2種類に分けて考慮して、傾きの積は-1に等しくて、あるいは平行と座標軸で、みんながどのように2点の直線の傾きを求めることを知っていると信じています.(i)番目の点の座標を((x_i,y_i))とすると、(i,j)番目の点を通過する直線の傾きが(frac{y_i-y_j}{x_i-x_i-x_j})となり、(y_i-y_j=0)の場合、その直線は(x)軸に平行であり、(x_i-x_j=0)の場合、その直線は(y)軸に平行である.
(500)個を超えない点しかないので、(frac{500times(500-1)}{2}=124750)を超えない直線しかありません.暴力が維持される場合、時間の複雑さは(O(n^4))である.
傾きを1つのデータ構造で維持することを考慮すると、(STL)のマッピングコンテナ(map)を使用して維持することは容易である.線分を1つ加えるたびに、増加した答えを統計します.
複雑度(O(Tn^2 log(n))
スレッド(1):
#include
using namespace std;
struct node{int x,y;}p[510];
map mp;
int T,n;
int main(){
scanf("%d",&T);
while(T--){
mp.clear();
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d %d",&p[i].x,&p[i].y);
int cnt1=0,cnt2=0;
long long ans=0;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(p[i].x==p[j].x) cnt1++;
else if(p[i].y==p[j].y) cnt2++;
else{
double x=(p[i].x-p[j].x),y=(p[i].y-p[j].y);
mp[x/y]++;
ans+=mp[-y/x];
}
}
}
printf("%lld
",ans*4+(long long)cnt1*cnt2*4);
}
}
スレッド(2):
#include
using namespace std;
struct node{int x,y;}p[510];
map,int> mp;
int T,n;
int gcd(int x,int y){
if(x%y==0) return y;
return gcd(y,x%y);
}
int main(){
scanf("%d",&T);
while(T--){
mp.clear();
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d %d",&p[i].x,&p[i].y);
int cnt1=0,cnt2=0;
long long ans=0;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(p[i].x==p[j].x) cnt1++;
else if(p[i].y==p[j].y) cnt2++;
else{
int x=(p[i].x-p[j].x),y=(p[i].y-p[j].y),gc=abs(gcd(x,y));
x/=gc;y/=gc;
if(x<0) x*=-1,y*=-1;
mp[make_pair(x,y)]++;
if(y<0) x*=-1,y*=-1;
ans+=mp[make_pair(y,-x)];
}
}
}
printf("%lld
",ans*4+(long long)cnt1*cnt2*4);
}
}
T 3迷宮の道を探す
この問題は主にみんなの広捜に対する理解を考察した.
前の(40)点に対して、直接深く探せばいい、(O(玄学)).
中間の(30)点については,広捜の古典的な例題であり,直接広捜,(O(nm))であることが容易にわかる.
すべてのデータについて、広捜を改良しようと試みた.広捜の思想は1つの優先キューを維持して、今距離の小さい位置を前に置いて、距離の大きい位置を後ろに置いて、本題の中でチームの頭とチームの尾の値の差は1を超えません.
現在、キューを取り出し、キューの距離を(dis)とし、トランスポートゲートを使用し、((i,j))位置に到達したと考えると、((i,j))の距離を(dis)に更新し、元のキューが最小であるため、直接キューに入れればよい.
さらに隣接する格子((i,j))まで歩くことを考慮して、距離は(dis+1)で、チームヘッドとチームテールの差は(1)より大きくないので、チームテールに入れればよい.
全複雑度(O(nm)).
スレッド:
#include
using namespace std;
int n,m,k,dis[2010][2010],vis[2010][2010],nxt[5][2]={{},{0,1},{0,-1},{1,0},{-1,0}};
char ch[2010][2010];
pair q[5000010];
vector > v[2010][2010];
int main(){
for(int i=0;i<=2005;i++){
for(int j=0;j<=2005;j++) ch[i][j]='#',dis[i][j]=2e9;
}
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++) scanf(" %c",&ch[i][j]);
}
scanf("%d",&k);
int x0,y0,x1,y1;
while(k--){
scanf("%d %d %d %d",&x0,&y0,&x1,&y1);
v[x0][y0].push_back(make_pair(x1,y1));
}
int l=1000000,r=1000000;
q[1000000]=make_pair(1,1);
dis[1][1]=0;
while(l<=r){
int x=q[l].first,y=q[l].second;
l++;
if(vis[x][y]) continue;
vis[x][y]=1;
for(int i=0;i
T 4家計簿の整理
この問題はビット演算に関する分析を少し受けた.
(i&(i-1))が何を表しているのか考えてみましょう.(10)を例にしてみましょう.(10&9=8)つまり((1010)2\&(1001)_2=(1000)_2)、つまりバイナリの下の最下位を外したことに相当します.
現在は(i)の最後の位置を考え、現在は右から左へ数える(k)位を考えると、彼の父は(i-2^{k-1})である.私たちは(2^{k-1}|i)を知ることができて、しかも(2^kmid i)なので、せっかく(2^k|i-2^k)を得ることができなくて、それから(i-2^kin[l,r])を知っているので、直接除算で([l,r])の中の(2^k)の倍数を統計すればいいので、境界が取れるかどうかを分類して考えてください.
複雑度(O(Tlog(値域)approx O(50 T)).
スレッド:
#include
using namespace std;
int n;
long long l,r;
int main(){
scanf("%d",&n);
while(n--){
scanf("%lld %lld",&l,&r);
long long ans=0;
for(int i=60;i>=1;i--){
long long nl=floor((double)(l-1)/(1LL<nr) continue;
if((nr<r) ans+=nr-nl;
else ans+=nr-nl+1;
}
printf("%lld
",ans);
}
}
完結散花QQQ