AtCoderグランドコンテスト問題の解決007

ポータル

\(\)

GUGU区

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=15;
char mp[N][N];int vis[N][N],n,m;
bool dfs(int x,int y){
    vis[x][y]=1;
    if(x==n&&y==m)return true;
    R int c=0;
    if(x<n&&mp[x+1][y]=='#')++c;
    if(y<m&&mp[x][y+1]=='#')++c;
    if(c!=1)return false;
    if(x<n&&mp[x+1][y]=='#')return dfs(x+1,y);
    if(y<m&&mp[x][y+1]=='#')return dfs(x,y+1);
}
int main(){
    scanf("%d%d",&n,&m);
    fp(i,1,n)scanf("%s",mp[i]+1);
    if(mp[1][1]!='#'||mp[n][m]!='#')return puts("Impossible"),0;
    if(!dfs(1,1))return puts("Impossible"),0;
    fp(i,1,n)fp(j,1,m)if((mp[i][j]=='#')!=vis[i][j])return puts("Impossible"),0;
    return puts("Possible"),0;
}

\(Bの\)

最初の\(A \)\(Bの\)のように設定されている(1 \)を\(\ N-)\第1、第2の条件を満足します

私たちは、場合ことがわかっ\は(a_iを\)する(A_N \)\すべての追加\(X- \) および\を(B_1 \)する(b_i \)\すべてが追加\(X- \) することができます(\しますa_iを+ b_i \)の相対的な増加\(X \)と、依然として第一条件に秒を満たします

だからせ\(P_I \)の相対的な増加\(iは\)第三の条件が満たされることができ、最大数である\(O(N ^ 2) \) を超えないレベル、\を(10 ^ 9 \)

const int N=1e5+5;
int a[N],b[N],p[N],n;
int main(){
    scanf("%d",&n);
    fp(i,1,n)scanf("%d",&p[i]),a[p[i]]+=i,b[p[i]]+=i;
    fp(i,1,n)a[i]+=a[i-1];fd(i,n,1)b[i]+=b[i+1];
    fp(i,1,n)printf("%d%c",a[i]+i," \n"[i==n]);
    fp(i,1,n)printf("%d%c",b[i]+n-i+1," \n"[i==n]);
    return 0;
}

\(C \)

全く予期しないああ......

まず、我々はに変換している\(2N + 1 \)項目THは、隣り合うをランダム削除、及び所望の距離を見つけます。

我々は最初から演算シーケンスであることを見出し、すべての2点間の距離を維持することが望ましい場合、一回の操作は依然として算術配列された後

特定証明次に、もし境界又は演算に明らかに2つの点を削除した後、または長さのためであれば\(D + KX \)の長さは、この後の2つの頂点を削除することによってなる(3D 3kx + \)を\理由であった\(D_I \)を表す\(Iは\)ポイントと\(I + 1 \)の点から所望の距離は、\(D_Iを「\)後の動作であります所望の距離、の次に合計\(2N \)種パンクチャリング方法、\(D_I「= {iが\ 2Nにわたって}(D_I + 2X)+ {2Nにわたって1 \}(3d_i + 3X)+ {2N-I -1 \ = {D_I} 2N + 2I上{D_I} + \ 2 + 2N 2Nを超える。3 \ 2N} X \)を超えるので、\(X '= d_i'-D_ {I-1} = {2N + 4 \ 2Xにわたって} = {X N-2 + \} \オーバーN-X) 固定値であります

再度削除した場合、最初のエントリの新しい演算シーケンスを考える\(2 \) 第1項はとなる(D + 2×\)を\削除した場合、\(3 \) 第1項はなります\(3X + 3D \) そうでなければ変化しないので、新たな最初の項目の\(D_1 ^ {「} = \ FRAC {1}、{2N} *(D_1 + 2X)+ \ FRAC {1}、{2N}(* 3d_1 + 3X)+ \ FRAC { 2N-2}、{2N} * D_1 = FRAC \ {(2N + 2)D_1 + 5X} {2N} \)

その後、各計算が可能

int n;double d,x,res;
int main(){
    scanf("%d%lf%lf",&n,&d,&x);
    for(;n;--n){
        res+=(d+((n<<1)-1)*x*0.5),
        d=(((n<<1)+2)*d+5*x)/(n<<1),
        x=(n+2)*x/n;
    }
    printf("%.12lf\n",res);
    return 0;
}

\(D \)

まず、激しい容易提供書き込み\(F_iと\)はフロント表す\(Iは\)時間内に処理されるすべての最小数、\(のf_i = \ MIN_ {J <I}(F_J + \ MAX(Tを(a_iを-A_ {J + 1 })))\)

以来、\(\ MAX(T、( a_iを-A_ {J + 1})\) カットオフ点はである\(Iは\)落とさないインクリメントので、回答の両側にそれぞれ我々ができ直接境界点(\セット\)を記録し、その後、直接のようなクエリ

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef long long ll;
const int N=5e5+5;const ll inf=1e18;
int n,t,e,a[N];ll f[N];
inline ll min(R ll x,R ll y){return x<y?x:y;}
inline ll max(R ll x,R ll y){return x>y?x:y;}
struct Queue{
    priority_queue<ll,vector<ll>,greater<ll> >A,B;
    inline void push(R ll x){A.push(x);}
    inline void pop(R ll x){B.push(x);}
    inline ll top(){
        while(!B.empty()&&A.top()==B.top())A.pop(),B.pop();
        return A.empty()?inf:A.top();
    } 
}s1,s2;
int main(){
    scanf("%d%d%d",&n,&e,&t);
    fp(i,1,n)scanf("%d",&a[i]);
    s2.push(0);
    for(R int i=1,j=0;i<=n;++i){
        while(j<i&&((a[i]-a[j+1])<<1)>=t)s1.push(f[j]-(a[j+1]<<1)),s2.pop(f[j]),++j;
        f[i]=inf,cmin(f[i],s1.top()+(a[i]<<1)),cmin(f[i],s2.top()+t);
        s2.push(f[i]);
    }
    printf("%lld\n",f[n]+e);
    return 0;
}

\(E \)

上半期は確かに答えになり、それぞれの側は、すべてのノードが出てくるために横断されたサブツリーを入力した後、二回通過することができますので、

各点について、記録状態は\((a、b)は\ ) 法的なパスが費やされている表し\(\)を過ごす、価格は現在のノードから葉に行ってきました\(B \)から価格を1は左のサブツリーのために、その後、現在のノードに戻って葉\((a、b)は\ ) と右のサブツリー\((C、D)\)ときにのみ\(B + w_i + C + w_j \ 当量中旬\)彼らはにまとめることができます\((A + w_i、w_jさd +)\) 共感も順次に組み合わせることができるかを決定\((C + w_j、B + w_i)\)

たびの合併に関する状態の息子限り、最終的に\(1 \)合法的な説明の有無のステータスドット\(中旬\)可能

最適化が正当用されてあります\(\) それに対応する\(のb \)は最初の右部分木によると、可能な限り小さくしなければならない、我々は左のサブツリーの最初の次元でソートすることができます2並べ替え、そのような複雑さを最適化するために組み合わせることができる\(O(n)を\)

しかし、状態の数は、私たちは状態多数をマージする状態の小さい番号を使用するたびに、そう状態の数より多くてもよい(S_U \のLeq 2 \分(S_I、S_j)\)\、状態の総数である(\しますO(N \ログn)が\ ) 、次いで合計複雑である\(O(N \ ^ログ )\ 2 n)を

しかし、より多くの奇妙な私は大規模な状態の少数を使用している場合ではないマージすることです\(T \)の代わりに\(WA \) ......ああ......良いのファンを

//quming
#include<bits/stdc++.h>
#define R register
#define pb push_back
#define fi first
#define se second
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef pair<int,int> pi;
typedef vector<pi> vc; 
const int N=5e5+5;
int ls[N],rs[N],w[N],mn[N],n,l,r,mid,ans;vc f[N];
inline int min(R int x,R int y){return x<y?x:y;}
inline void swap(R int &x,R int &y){R int t=x;x=y,y=t;}
inline bool cmpx(const pi &x,const pi &y){return x.fi<y.fi;}
inline bool cmpy(const pi &x,const pi &y){return x.se<y.se;}
void merge(vc &a,vc &ls,vc &rs){
    R int n=ls.size(),m=rs.size();
    if(!n||!m)return;
    if(n>m)ls.swap(rs),swap(n,m);
    sort(ls.begin(),ls.end(),cmpy);
    sort(rs.begin(),rs.end(),cmpx);
    mn[0]=rs[0].se;fp(i,1,m-1)mn[i]=min(mn[i-1],rs[i].se);
    for(R int i=0,j=m-1;i<n;++i){
        while(j>=0&&ls[i].se+rs[j].fi>mid)--j;
        if(j<0)break;a.pb(pi(ls[i].fi,mn[j]));
    }
    sort(ls.begin(),ls.end(),cmpx);
    sort(rs.begin(),rs.end(),cmpy);
    mn[0]=rs[0].fi;fp(i,1,m-1)mn[i]=min(mn[i-1],rs[i].fi);
    for(R int i=0,j=m-1;i<n;++i){
        while(j>=0&&ls[i].fi+rs[j].se>mid)--j;
        if(j<0)break;a.pb(pi(mn[j],ls[i].se));
    }
}
void dfs(int u){
    f[u].clear();if(!ls[u])return f[u].pb(pi(w[u],w[u])),void();
    dfs(ls[u]),dfs(rs[u]);
    merge(f[u],f[ls[u]],f[rs[u]]);
    for(auto &v:f[u])v.fi+=w[u],v.se+=w[u];
}
int main(){
    scanf("%d",&n);
    for(R int i=2,fa,x;i<=n;++i){
        scanf("%d%d",&fa,&x);
        (ls[fa]?rs[fa]:ls[fa])=i,w[i]=x;
    }
    l=0,r=1e9,ans=1e9;
    while(l<=r){
        mid=(l+r)>>1,dfs(1);
        f[1].empty()?l=mid+1:(ans=mid,r=mid-1);
    }
    printf("%d\n",ans);
    return 0;
}

\(F \)

グッドファン......

まず、私たちは一つのパスと見なさトラックダウン手紙を見つけ、このパスは、ポリライン、ポリラインと早いほど良いターニングなります

だから我々はしなければならない(のt \)を\見つかっ、貪欲なマッチの後ろから\(S \)と一致する最後尾のことで位置をした後、以前のポリラインの交差点があるかどうかを判断します

私はまだ気持ちは非常に明確ではないと言う......私は、公式の問題に図ソリューションを見てお勧めします

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=1e6+5;
char a[N],b[N];int q[N],h,t,n,res;
int main(){
    scanf("%d%s%s",&n,a+1,b+1);
    if(!strcmp(a+1,b+1))return puts("0"),0;
    h=1,t=0;
    for(R int i=n,p=n;i;--i)if(b[i]!=b[i-1]){
        cmin(p,i);while(p&&a[p]!=b[i])--p;
        if(!p)return puts("-1"),0;
        while(h<=t&&q[h]-(t-h+1)>=i)++h;
        q[++t]=p;
        if(i!=p)cmax(res,t-h+1);
    }
    printf("%d\n",res+1);
    return 0;
}

おすすめ

転載: www.cnblogs.com/yuanquming/p/11438531.html
おすすめ