2019 CIPC Asia Nanjing regional

2019 CIPC Asia Nanjing regional

A - duro Problema

metro ajo fuera --42 395

Si n = 10, primero puede tomar: 6,7,8,9,10. A continuación, sólo elegir uno desde el interior de 1,2,3,4,5 son ciertamente consistente con el significado de problemas

Si n = 9, primero puede tomar: 5,6,7,8,9, y luego casualmente seleccionado de 1,2,3,4, que son sin duda en línea con un significado de las preguntas.

Así que la respuesta es la última mitad de la cantidad de 1

#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 100000 + 5;

int T, n;

int main() {
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        if(n & 1)printf("%d\n",n/2+2);
        else printf("%d\n", n/2+1);
    }
    return 0;
}

B.Chessboard

En primer lugar, cuando el \ (n = 1 \) o \ (m = 1 \) sólo cuando los dos métodos, el cepillo de arriba hacia abajo o un cepillo de abajo hacia arriba, la salida de frase japonesa 2.

Considere el caso general.

¿Cómo tipo de estrategia de estuco es ilegal?

Cuando me cepillo con el cepillo con una protuberancia que es ilegal.

Porque acabo pieza saliente debe ser capaz de conducir a la distancia entre un par de color pintado caja más grande que la distancia Manhattan.

Así que la situación legal es, sólo una vez o añadir una línea o un aumento.

Por lo que desde el comienzo \ (1 \ times 1 \) matriz se convierte en \ (n \ M veces \) matriz requiere \ (n + m-2 \ ) operaciones, incluyendo \ (n-1 \) veces es la expansión de la línea, por lo que la respuesta es: \ (. + C_ {n-m-2}} 1-n- ^ {\) .

Porque cada vez que estamos añadiendo una línea, o un aumento, por lo que debe terminar en las cuatro esquinas, por lo que finalmente, a la respuesta multiplicado por cuatro.

Aquí, he utilizado \ \ (Lucas) a escribir, de hecho, también puede ser \ (nlogn \) después del pretratamiento (O (1) \) \ resultados, pero de todos modos, no se preocupan.

#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
const int maxn = 1e6+10;
typedef long long ll;
int n, m;
ll fact[maxn];
ll qmi(ll a, ll b, ll p)
{
    ll res = 1; res %= p;
    while(b)
    {
        if(b & 1) res = res*a%p;
        a = a*a%p;
        b >>= 1;
    }
    return res;
}

ll C(ll n, ll m, ll p)
{
    if(m > n) return 0;
    return ((fact[n]*qmi(fact[m],mod-2,mod))%mod*qmi(fact[n-m],mod-2,mod)%mod);
}

ll lucas(ll a, ll b, ll p)
{
    if(b == 0) return 1;
    return C(a%p, b%p, p) * lucas(a/p, b/p, p) % p;
}

void solve()
{
    scanf("%d%d", &n, &m);
    if(n == 1 || m == 1)
    {
        puts("2");
        return;
    }

    ll ans = lucas(n+m-2, n-1, mod);
    ans = (ans*4)%mod;
    printf("%lld\n", ans);
}

int main()
{
    fact[0] = 1;
    for(int i = 1; i <= (int)1e6; i++)
        fact[i] = (fact[i-1]*i)%mod;
    int T; scanf("%d", &T);
    while(T--) solve();
    return 0;
}

Ruta Digital - C

El ajo metros fuera --42 397

Dos puntos adyacentes si la diferencia de peso es 1, de pequeño a borde grande y uniforme. Luego, al final, ya que es un DAG, DAG en la secuencia anterior DP a la topología.

#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 1000000 + 5;
const int M = 4000005;
const int mod = 1e9 + 7;
int head[N], ver[M], nxt[M], edge[M], deg[N], tot;
int ends[N];
void add(int x, int y){
    deg[y]++;
    ver[++tot] = y, nxt[tot] = head[x], head[x] = tot;
}
int n, m, a[1010][1010];
ll d[N][5];// d[x][4]表示以x为终点,长度大于等于4的路径个数,d[x][3]表示长度等于3的路径个数,其他类似
inline int id(int x, int y){
    return (x-1)*m+y;
}
int main() {
    scanf("%d%d",&n,&m);
    memset(a, 0xcf, sizeof a); //注意这里的初始化
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&a[i][j]);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            int x = id(i, j);
            if(a[i+1][j] == a[i][j] + 1) add(x, id(i+1,j));
            if(a[i][j+1] == a[i][j] + 1) add(x, id(i,j+1));
            if(a[i-1][j] == a[i][j] + 1) add(x, id(i-1,j));
            if(a[i][j-1] == a[i][j] + 1) add(x, id(i,j-1));
        }
    }
    queue<int> q;
    for(int i=1;i<=n*m;i++)if(deg[i] == 0)q.push(i),d[i][1] = 1;
    ll res = 0;
    while(q.size()){
        int x = q.front();q.pop();
        bool flag = true;
        for(int i=head[x];i;i=nxt[i]){
            int y = ver[i];
            d[y][2] = (d[y][2] + d[x][1]) % mod;
            d[y][3] = (d[y][3] + d[x][2]) % mod;
            d[y][4] = (d[y][4] + d[x][3] + d[x][4])%mod;
            if(--deg[y] == 0)q.push(y);
            flag = false;
        }
        if(flag) res = (res + d[x][4])%mod;//如果出度为0则记录到答案中
    }
    printf("%lld\n",res);
    return 0;
}

F - Clasificación de papel

El ajo metros fuera --42 400

se añaden trie primeras cuerdas, seguido de la etiqueta \ (f [i] \) como el último carácter de cada cadena de caracteres especificada nodos trie, considere cada interrogatorio, para descender en los tiempos Trie K, para la situación legal se puede encontrar en los nodos, la respuesta es \ (f [l..r] \) , el número pertenece al punto de unión legítima del árbol.

Aquí, no se considera una operación de modificación, se puede establecer un árbol de Trie por orden Presidente DFS, \ (DFN [i] \) representa un nodo i-ésimo orden DFS, entonces cada \ (F [i] \) , en el \ (dfn [f [i] ] \) árboles pesos segmento de árbol \ (\ I) hecho +1 valor de peso de la ubicación, y la consulta cada intervalo de subárbol cuántos números están en la \ ([l, r ] \) en el intervalo.

Plus operación de modificación se puede utilizar para mantener el árbol árbol segmento de pesos del sistema, el intercambio de la posición de dos cadenas, es decir, un intercambio de $ f [i] $, puede modificar directamente el árbol segmento de pesos

#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 200000 + 5;
int n, m, L[30][30], R[30][30], cl, cr;
int f[N];
char s[N];
inline int lowbit(int x){return x & -x;}
struct SEG{
    struct node{
        int ls,rs;
        int sum;
    }t[N*200];
    int rt[N], tot, maxn, res;
    void update(int &rt, int l, int r, int pos, int val){
        if(!rt) rt = ++tot;
        t[rt].sum += val;
        if(l == r)return;
        int mid = l + r >> 1;
        if(pos <= mid) update(t[rt].ls, l, mid, pos, val);
        else update(t[rt].rs, mid+1, r, pos, val);
    }
    void update(int x, int pos, int v){
        for(;x<=maxn;x+=lowbit(x))update(rt[x],1,n,pos,v);
    }
    void query(int dep, int l, int r, int ql, int qr){
        if(ql > qr) return;
        if(l >= ql && r <= qr){
            for(int i=1;i<=cl;i++) res -= t[L[dep][i]].sum;
            for(int i=1;i<=cr;i++) res += t[R[dep][i]].sum;
            return;
        }
        int mid = l+r>>1;
        if(ql <= mid){
            for(int i=1;i<=cl;i++)L[dep+1][i] = t[L[dep][i]].ls;
            for(int j=1;j<=cr;j++)R[dep+1][j] = t[R[dep][j]].ls;
            query(dep+1,l,mid,ql,qr);
        }
        if(qr > mid){
            for(int i=1;i<=cl;i++)L[dep+1][i] = t[L[dep][i]].rs;
            for(int j=1;j<=cr;j++)R[dep+1][j] = t[R[dep][j]].rs;
            query(dep+1,mid+1,r,ql,qr);
        }
    }
}seg;
struct Trie{
    int ch[N][26], tot;
    int dfn[N], cid[N], out[N], cnt;
    int ins(char *s){
        int p = 1, len = strlen(s);
        for(int i=0;i<len;i++){
            int c = s[i] - 'a';
            if(!ch[p][c]) ch[p][c] = ++tot;
            p = ch[p][c];
        }
        return p;
    }
    void dfs(int x){
        dfn[x] = ++cnt, cid[cnt] = x;
        for(int i=0;i<26;i++){
            if(ch[x][i]) dfs(ch[x][i]);
        }
        out[x] = cnt;
    }
    int find(char *s, int k){
        int p = 1;
        for(int i=0;i<k;i++){
            int c = s[i] - 'a';
            if(!ch[p][c]) return -1;
            p = ch[p][c];
        }
        return p;
    }
}trie;

int main() {
    scanf("%d%d",&n,&m);
    trie.tot = 1;
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        f[i] = trie.ins(s);
    }
    trie.dfs(1);
    seg.maxn = trie.cnt;//maxn为权值线段树的个数
    for(int i=1;i<=n;i++){
        f[i] = trie.dfn[f[i]];//这里将f进一步映射到了Trie结点的dfs序上
        seg.update(f[i], i, 1);
    }
    while(m--){
        int op, l, r, k;
        scanf("%d",&op);
        if(op == 1){
            scanf("%d%d",&l,&r);
            seg.update(f[l], l, -1);
            seg.update(f[r], r, -1);
            seg.update(f[r], l, 1);
            seg.update(f[l], r, 1);
            swap(f[l], f[r]);
        }else {
            scanf("%s%d%d%d",s, &k, &l, &r);
            int pos = trie.find(s, k);
            if(pos == -1){
                printf("0\n");continue;
            }
            int x = trie.dfn[pos]-1, y = trie.out[pos];
            cl = cr = 0;
            for(int j=x;j;j-=lowbit(j))L[0][++cl] = seg.rt[j];
            for(int j=y;j;j-=lowbit(j))R[0][++cr] = seg.rt[j];
            seg.res = 0;
            seg.query(0, 1, n, l, r);
            printf("%d\n",seg.res);
        }
    }
    return 0;
}

H - Príncipes

metro ajo fuera --42 402

a = 1, b = 0, c = 0, entonces res = 0

a> 1, b = 0, c = 0 则 res = 1

a> b, b> 0, c = 0, entonces el peor de los casos necesidad de pedir 2 * b + 1 personal "princesa en esa habitación," vamos a conseguir un b + 1 veces la respuesta

a <b, b> 0, c = 0, a continuación, cada uno con un B puede responder a la misma respuesta (porque son mentirosos), es imposible distinguir, no se puede obtener el resultado correcto

a> b + c, el tercer enfoque similar para preguntar sobre 2 * (b + c) +1 veces la "princesa en esa habitación," apareció más veces es la respuesta

un <b + c, ninguna solución

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;

int main() {
    int a, b, c;
    scanf("%d%d%d", &a, &b, &c);
    if(c == 0) {
        if(b == 0) {
            puts("YES");
            if(a == 1) puts("0");
            else puts("1");
        } else if(a > b) {
            puts("YES");
            printf("%d\n", b + b + 1);
        } else {
            puts("NO");
        }
    } else {
        if(a > b + c) {
            puts("YES");
            printf("%d\n", b + c + b + c + 1);
        } else {
            puts("NO");
        }
    }
    return 0;
}

J - Spy

metro ajo fuera --42 404

En primer lugar se convierta en un problema bipartito gráfico coincidencia máxima ponderada, y luego utilizar el algoritmo KM de resolver.

dfs versión KM, cada vez que un recursiva sólo aumentan en un borde igual a la sub-dibujo, y son cada uno límite de recursión \ (O (M) \) la complejidad, por lo que cuando \ (M = N ^ 2 \ ) cuando , la complejidad alcanzará \ (O (N ^. 4) \) ,

Incluso la adición de \ (\ holgura) valor mínimo de datos grabado está optimizado, no se puede evitar tal situación.

BFS versión KM, es la complejidad de cada BFS \ (O (M) \) , pero se expandirá cada BFS \ (O (N) \) bordes, la complejidad global es \ (O (N ^ 3 ) \) de

Referencia: https://blog.csdn.net/c20182030/article/details/73330556

#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 605;

ll n, a[N],b[N],c[N],p[N];
ll w[N][N];
ll lx[N] , ly[N];
ll match[N];
ll slack[N];
bool vy[N];
ll pre[N];
void bfs( ll k ){
    ll x , y = 0 , yy = 0 , delta;
    memset( pre , 0 , sizeof(pre) );
    for( ll i = 1 ; i <= n ; i++ ) slack[i] = inf;
    match[y] = k;
    while(1){
        x = match[y]; delta = inf; vy[y] = true;
        for( ll i = 1 ; i <= n ;i++ ){
            if( !vy[i] ){
                if( slack[i] > lx[x] + ly[i] - w[x][i] ){
                    slack[i] = lx[x] + ly[i] - w[x][i];
                    pre[i] = y;
                }
                if( slack[i] < delta ) delta = slack[i] , yy = i ;
            }
        }
        for( ll i = 0 ; i <= n ; i++ ){
            if( vy[i] ) lx[match[i]] -= delta , ly[i] += delta;
            else slack[i] -= delta;
        }
        y = yy ;
        if( match[y] == -1 ) break;
    }
    while( y ) match[y] = match[pre[y]] , y = pre[y];
}
 
ll KM(){
    memset( lx , 0 ,sizeof(lx) );
    memset( ly , 0 ,sizeof(ly) );
    memset( match , -1, sizeof(match) );
    for( ll i = 1 ; i <= n ; i++ ){
        memset( vy , false , sizeof(vy) );
        bfs(i);
    }
    ll res = 0 ;
    for( ll i = 1 ; i <= n ; i++ ){
        if( match[i] != -1 ){
            res += w[match[i]][i] ;
        }
    }
    return res;
}
 
int main()
{
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++) scanf("%lld",&a[i]);
    for(ll i=1;i<=n;i++) scanf("%lld",&p[i]);
    for(ll i=1;i<=n;i++) scanf("%lld",&b[i]);
    for(ll i=1;i<=n;i++) scanf("%lld",&c[i]);
    for(ll i=1;i<=n;i++){
        for(ll j=1;j<=n;j++){
            ll s=0;
            for(ll k=1;k<=n;k++){
                if(b[i]+c[j]>a[k]) s+=p[k];
            }
            w[i][j]=s;
        }
    }
    printf("%lld\n",KM());
    return 0;
}

K.Triangle:

Esta pregunta es más difícil de lo que parece a escribir.

En primer lugar, no considerar el punto en que no en línea, que es una placa en vivo, principio que no sé cómo, se encontró una copia de la junta por un momento.

A continuación, un par de circunstancias especiales, \ (P \) puntos y los tres vértices de un triángulo \ (A, B, C \ ) coinciden, entonces debe ser el punto medio del borde.

La idea aquí podemos encontrar una buena propiedad.

Asumo que los puntos caen \ (AB \) en adelante, si el punto de \ (A \) Más recientemente, otro punto debe caer \ (AC \) en; si por \ (B \) más cerca, por lo otro punto debe caer \ (AC \) ; si cae \ (AB \) del punto medio, a continuación, el otro punto es el vértice del triángulo.

Por lo tanto, los ajustes de punto, de modo que los puntos se encuentran \ (AB \) cerca \ (A \) en su lugar, y luego otra distancia punto medio \ (C \) relación de longitud de la longitud de la última calculada en el punto de coordenadas puede ser a.

Debido a que el objeto de la solicitud \ (1E-6 \) , así que me puse \ (EPS = 1E-8 \) , abierta \ (Doble \) , no saben que no hay otros problemas de precisión.

Nota: la longitud del lado por delante de tratamiento necesario, reducir las funciones de biblioteca de llamadas.

#include<bits/stdc++.h>
using namespace std;
typedef double ld;
ld eps = 1e-8;

struct Point{
    ld x, y;
}a, b, c, p, q;
ld area;
ld ab, ac, bc, ap, bp;

bool onSegment(Point Pi, Point Pj, Point Q)
{
    if((Q.x - Pi.x) * (Pj.y - Pi.y) == (Pj.x - Pi.x) * (Q.y - Pi.y)  //叉乘
       //保证Q点坐标在pi,pj之间
       && min(Pi.x , Pj.x) <= Q.x && Q.x <= max(Pi.x , Pj.x)
       && min(Pi.y , Pj.y) <= Q.y && Q.y <= max(Pi.y , Pj.y))
        return true;
    else
        return false;
}

ld dist(Point a, Point b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

bool check(ld mid, ld sinb)
{
    ld are = sinb*(bp)*(bc-mid)/2;
    if(are*2.0 >= area) return 0;
    return 1;
}

void solve()
{
    scanf("%lf%lf%lf%lf%lf%lf%lf%lf", &a.x, &a.y, &b.x, &b.y, &c.x, &c.y, &p.x, &p.y);
    //cin>>a.x>>a.y>>b.x>>b.y>>c.x>>c.y>>p.x>>p.y;
    if(!onSegment(a, b, p)&&!onSegment(b, c, p)&&!onSegment(a, c, p))
    {
        puts("-1");
        return;
    }

    //先看看会不会在某个点上
    if(p.x == a.x && p.y == a.y)
    {
        //输出bc中点
        q.x = (b.x+c.x)/2.0;
        q.y = (b.y+c.y)/2.0;
        //cout << setprecision(10) << q.x << " " << q.y << endl;
        printf("%.10f %.10f\n", q.x, q.y);
        return;
    }
    else if(p.x == b.x && p.y == b.y)
    {
        //ac中点
        q.x = (a.x+c.x)/2.0;
        q.y = (a.y+c.y)/2.0;
        //cout << setprecision(10) << q.x << " " << q.y << endl;
        printf("%.10f %.10f\n", q.x, q.y);
        return;
    }
    else if(p.x == c.x && p.y == c.y)
    {
        //ab中点
        q.x = (a.x+b.x)/2.0;
        q.y = (a.y+b.y)/2.0;
       // cout << setprecision(10) << q.x << " " << q.y << endl;
        printf("%.10f %.10f\n", q.x, q.y);
        return;
    }


    //把点弄到ab上
    if(onSegment(a, b, p)) {}
    else if(onSegment(b, c, p)) swap(a, c);
    else if(onSegment(a, c, p)) swap(b, c);

    //距离b更近一点
    if(dist(a, p) > dist(b, p)) swap(a, b);

    //开始搞
    ab = dist(a, b);
    ac = dist(a, c);
    bc = dist(b, c);
    ap = dist(a, p);
    bp = dist(b, p);

    ld p = (ab+bc+ac)/(ld)2.0;
    area = sqrt(p*(p-ab)*(p-bc)*(p-ac));
    ld sina = area*2/ab/bc;
    //area = ab*bc*sinb/2
    //sina = area*2/ab/bc

    ld l = 0.0, r = bc;
    while(l+eps < r)
    {
        ld mid = (l+r)/(ld)2.0;
        if(check(mid, sina)) r = mid;
        else l = mid;
    }

    ld len = l;
    //输出点
    q.x = (b.x-c.x)*len/bc+c.x;
    q.y = (b.y-c.y)*len/bc+c.y;
    //cout << setprecision(10) << q.x << " " << q.y << endl;
    printf("%.10f %.10f\n", q.x, q.y);
    return;
}

int main()
{
    int T; scanf("%d", &T);
    while(T--) solve();
    return 0;
}

Supongo que te gusta

Origin www.cnblogs.com/1625--H/p/12468117.html
Recomendado
Clasificación