zoukankan      html  css  js  c++  java
  • 沈阳集训day3

    问题 A: 老光棍

    题目描述

    L君和G君在玩一个游戏。G君写下一个字符串A,L君将其复制一遍连接到A串后面得到字符串B,G君又在B的任意位置(包括首尾)插入一个字符得到字符串C。现在你得到了C,请你找出A。

    输入

    第一行一个整数T,表示有T组数据
    每组数据第一行一个整数 n,表示字符串 C 的长度。
    每组数据第二行 n 个大写字母,表示字符串 C。

    输出

    若不存在可能的字符串 A,输出一行“NOT POSSIBLE” ;若存在多个不同的字符串 A 满足条件,输出一行“NOT UNIQUE” ;否则输出一行为满足条件的字符串 A。

    样例输入

    1
    5
    ZGZGZ

    样例输出

    NOT UNIQUE

    提示

    对于50%的数据,满足2 ≤ n ≤ 2000。

    对于100%的数据,满足T ≤ 10,2 ≤ n ≤ 1000001。

    部分数据随机。
    题解:O(n) 枚举长度, O(1)hash查询是否满足, 如果前半部分可以去掉一个, 后半部分也可以去掉一个, 那么还要比较两个模板是否一样, 那么要去掉,判断细节比较多
    #include <iostream>
    #include<cstdio>
      
    using namespace std;
    const int bas = 2333, maxn = 1000005;
    int n, rightpos,has[maxn], base[maxn];
    char s[maxn];
    void init(){
        base[0] = 1;
        for(int i = 1; i <= n; i++)
            has[i] = has[i-1] * bas + s[i-1], base[i] = base[i-1] * bas;
    }
    bool check(int pos){
        int st1, ed1, a, b , c, d;
        if(pos == 1){
            a = has[n/2+1]-has[1]*base[n/2], c = has[n] - has[n/2+1]*base[n/2];
            b = d = 0;
        }
        else if(pos == n){
            a = has[n/2], c = has[n-1] - has[n/2] * base[n/2];
            b = d = 0;
        }
         else if(pos == n/2 +1){
            a = has[n/2], c = has[n] - has[n/2+1]*base[n-n/2-1];
            b = d = 0;
        }
        else if(pos <= n/2){
            st1 = n/2 + 1;
            ed1 = n/2 + pos,
            a = has[pos-1], b = has[n/2+1] - has[pos]*base[n/2-pos+1];
            c = has[ed1] - has[st1]*base[ed1-st1], d = has[n] - has[ed1]*base[n-ed1];
        }
        else if(pos > n/2){
            st1 = pos-n/2-1;
            a = has[st1], b = has[n/2] - has[st1]*base[n/2-st1];
            c = has[pos-1] - has[n/2]*base[pos-1-n/2], d = has[n]-has[pos]*base[n-pos];
        }
         
        if((a==c) && (b==d)){
            rightpos = pos;return 1;
        }
        return 0;
      
      
    }
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--){
            int cnt = 0;
            scanf("%d", &n);
            scanf("%s", s);
            init();
            int fg1 = 0, fg2 = 0;
            if(n%2 == 0){
                puts("NOT POSSIBLE");
                continue;
            }
            for(int i = 1; i <= n/2; i++)
                if(check(i)){
                    fg1 = 1;break;
                }
            for(int i = n/2+2; i <= n; i++)
                if(check(i)){
                    fg2 = 1; break;
                }
             
            if(fg1 && fg2)
                if(check(n/2+1)) cnt = 1;
                    else cnt = 2;
            else if(fg1 || fg2) cnt = 1; 
             
            if(check(n/2+1))cnt = 1;
            if(cnt == 1){
                if(rightpos <= n/2){
                     for(int i = 1; i <= n/2+1; i++)
                         if(i!=rightpos)printf("%c",s[i-1]);
                }      
               else {
                   for(int i = n/2+1; i <= n; i++)
                      if(i!=rightpos)printf("%c", s[i-1]);    
                }
                    printf("
    ");   
            }
            else if(cnt > 1)puts("NOT UNIQUE");
            else puts("NOT POSSIBLE");
        }
    }
    View Code

    问题 B: 饼干

    题目描述

    佩琪和贝茜是好朋友。
    佩琪最喜欢吃饼干了!但是现在他不准备自己吃,她决定和贝茜分享自己的饼干。佩琪有四种口味的饼干,分别是巧克力味、香草味、红豆味和椰子味。可惜的是,佩琪已经把椰子味的饼干全吃光了,所以现在只剩下前三种了233。。。
    巧克力味饼干能带来A的美味度,香草味饼干能带来B的美味度,而红豆味饼干可以带来A+B的美味度。
    佩琪会拿出不多于N块饼干作为送给贝茜的礼物。
    为了显得真诚,她想让她拿出的饼干的美味度之和恰好为K。
    为了显得体面,她决定用一个精美的盒子来装这些饼干。盒子内部有N个位置,每个位置都可以放一块饼干,或者不放。
    现在佩琪想知道有多少种方案可以既显得真诚又显得体面。两种方案不同,当且仅当盒子中某个位置放置的饼干味道不同,或者一个放了饼干而另一个没有。
    佩琪自己当然不会做啦,所以她决定请你来帮她解决这个问题。为了防止答案过大,你只需要告诉她答案对998244353取模的结果就行了。

    输入

    输入只有一行,包含四个整数,分别为N、A、B、K。

    输出

    输出一行一个整数,即答案对998244353取模的结果。

    样例输入

    4 1 2 5

    样例输出

    40

    提示

    对于前30%的数据,1≤N≤10,0≤K≤500

    对于前50%的数据,1≤N≤1000,0≤K≤3000;

    对于前80%的数据,1≤N≤1e5,0≤K≤2e10;

    对于100%的数据,1≤N≤1e7,0≤K≤1e15,0≤A,B ≤1e5。

    题解:我们可以求出n个盘子里放m个苹果的方案, 美味度可以枚举a的数量,b的数量也确定了, 那么a+b怎么办呢?

    我们发现没有限制的放a, 没有限制的放b, 有些就会又放a又放b, 相当于a+b, 是不是很妙? 所以方案数 = C(a) * C(b) 。

    还要, 这又是一道细节多的要死的题;

    #include<iostream>
    #include<cstdio>
    #define p 998244353
    #define ll long long
    using namespace std;
    const int maxn = 1e7 + 5;
    ll fac[maxn];
    ll a, b, k, n;
    ll ans;
    ll mi(long long a,long long b)
    {
        long long anss=1;
        for(;b;b>>=1,a=a*a%p)
           if(b&1) anss=anss*a%p;
        return anss;
    }
    ll exgcd(ll a, ll b, ll &x, ll &y){
        if(b == 0){
            x=1;y=0;return a;
        }
        ll x0, y0;
        ll d = exgcd(b, a%b, x0, y0);
        x = y0;
        y = x0 - (a/b)*y0;
        return d;
    }
    ll in(ll a){
        ll x, y;
        exgcd(a, p, x, y);
        return (x%p + p) %p;
    }
    ll C(ll pp, ll q){
        return fac[n] * in(fac[pp]) % p * in(fac[n-pp])  % p * fac[n] %p * in(fac[q]) %p *in(fac[n-q]) % p;
    }
    int main ( ) {
        scanf ( "%lld%lld%lld%lld", &n, &a, &b, &k );
        fac[0] = 1;
        for(ll i = 1; i <= n; i++)
            fac[i] = fac[i-1]*i % p;
        if(a==0&&b!=0) swap(a,b);
        if(!a && !b&&k!=0) ;
        else if(!a&&!b&&!k)
          ans=mi(4,n);
        else if(!b){
            int fg = 0;
            if(k % a) fg = 1;
            int t = k/a;
            if(fg == 0)
                ans = fac[n] * in(fac[t]) % p * in(fac[n-t]) % p*mi(2,n)%p;
                     
        }
        else {
            for(ll i = 0; i <= n; i++)
                if(i * a > k)break;
                else if( (k - a*i) % b == 0){
                    ll t = (k - a*i) / b;
                    if(t <= n)ans = (ans + C(i , t)) % p;
                    //printf("%lld  ", ans);
                }   
        }
        printf ("%lld", ans);
        return 0;
    }
    View Code

    问题 C: 空间宝石

    题目描述

    zP1nG很清楚自己打不过灭霸,所以只能在自己出的题里欺负他。
    咳咳。
    这一次他得到了空间宝石Tesseract。
    世界之树连接着九界,此时灭霸和zP1nG都在九界的某个地方。而九界是相互无法到达的。zP1nG为了追杀灭霸,决定使用空间宝石的力量到达灭霸身边。因为zP1nG不擅长使用空间宝石,无法直接开一条从自己的位置到灭霸的位置的传送门,所以他只能无意识地使用空间宝石的力量。zP1nG想知道,在自己胡乱地使用空间宝石后,通过传送门到达灭霸的位置最少需要多长时间。
    具体地,九界的编号为0~8,共有n道传送门,第i道传送门为优先级为pi,由ui到vi,需要花费wi个时间的单向门。传送的规则为:zP1nG按顺序穿过的传送门的优先级必须是单调不降的。例如,zP1nG穿过了三道传送门到达灭霸的位置,这三道传送门的优先级分别为1→2→2即为一种合法的方式,而优先级分别为1→2→1是不合法的。
    zP1nG会使用q次宝石的力量来尝试进行传送:其中第i次尝试会打开数道传送门,这些传送门的优先级会形成si个区间。例如,在某次尝试中zP1nG打开了三个区间[1,2],[4,7],[9,10],那么优先级在这三个区间内的传送门将全部被打开并允许zP1nG穿过。你需要告诉zP1nG在此情况下从自己的位置zi到达灭霸所在处ti所需的最短时间。尝试结束后所有传送门会关闭

    输入

    第1行包含两个正整数n和S,S的含义见数据范围与约定所述。
      第2至n+1行每行包含4个正整数pi,ui,vi,wi。
      第n+2行包含一个正整数q。
      第n+3至第n+q+2行每行若干个正整数,其中前三个数为zi,ti,si,之后为2*si个正整数,表示每个区间的左右端点。
      各变量具体含义见题目描述所述。

    输出

    对于zP1nG进行的每次尝试,输出一行一个数表示从zP1nG的位置到灭霸的位置所需的最短时间,如果zP1nG无法到达灭霸的位置则输出-1。

    样例输入

    6 2
    1 2 4 1
    2 1 3 3
    3 1 2 2
    4 3 4 5
    5 2 4 3
    6 1 4 2
    4
    1 4 1 1 3
    1 4 1 1 4
    1 4 2 5 5 2 3
    1 4 1 1 6

    样例输出

     -1
     8
     5
     2

    提示

     

     
    题解:这是一个神奇的解法,我们发现矩阵乘法是
    a[i][j] = sum( b[i][k] + c[k][j] ); 如果把他改成a[i][j] = min( b[i][k] + c[k][j] ), 是不是就成Floyd了;
    表示从i 到 j的最短路;那么优先级怎么办?——线段树;
    每个优先级开一棵线段树,只能从优先级低的地方更新过来,所以询问的时候排一道序,然后用线段树合并,因为矩阵a[i][j]表示的是从i到j,所以必须要按优先级更新(思考为什么)
    #include <bits/stdc++.h>
     
    using namespace std;
    #define maxn 10005
    #define inf 1000000008
    const int lim = 2005;
    struct Q{
        int l, r;
    }q[maxn];
    /*struct Edge{
        int p, u, v, w;
    }e[maxn];
    bool cmp2(Edge a, Edge b){
        return a.p < b.p;
    }*/
    bool cmp(const Q &a,const Q &b){
        return a.l < b.l;
    }
     
    int tot;
    struct  Maxtri{
        int dis[10][10];
     
        void init(){
            for(int i = 0; i <= 8; i++)
                for(int j = 0; j <= 8; j++)
                    dis[i][j] = (i == j) ? 0 : inf;
        }
     
    }G[lim+1];
    Maxtri merge(Maxtri a, Maxtri b){
        Maxtri c;
        c.init();
        for(int k = 0; k < 9; k++)
            for(int i = 0; i < 9; i++)
                for(int j = 0; j < 9; j++)
                    c.dis[i][j] = min(c.dis[i][j], a.dis[i][k]+b.dis[k][j]);
        return c;
     
    };
     
     
    struct Node {
        Node * ls, * rs;
        Maxtri now;
    }pool[lim << 2], *tail = pool, *root;
     
    Node * build(int l = 1, int r = lim){
        Node * nd = ++tail;
        if(l == r)nd -> now = G[l];
        else {
            int m = (l + r) >> 1;
            nd -> ls = build(l, m);
            nd -> rs = build(m+1, r);
            nd -> now = merge(nd -> ls -> now, nd -> rs ->now);
        }
        return nd;
    }
    #define Ls l, mid, nd -> ls
    #define Rs mid+1, r, nd -> rs
    Maxtri query(int L, int R, int l = 1, int r = lim, Node * nd = root){
        if(L <= l && R >= r)return nd->now;
     
        int mid = (l + r) >> 1;
        Maxtri ans;
        bool fg = 0;
        if(L <= mid){
            ans = query(L, R, Ls);
            fg = 1;
        }
        if(R > mid)
            if(fg) ans = merge(ans, query(L, R, Rs));
            else ans = query(L, R, Rs);
        return ans;
    }
    int main(){
        int cas, n, S;
        scanf("%d%d", &n, &S);
        for(int i = 1; i <= lim; i++)G[i].init();
        for(int i = 1; i <= n; i++){
            int p, u, v, w;
            scanf("%d%d%d%d", &p, &u, &v, &w);
            G[p].dis[u][v] = min(G[p].dis[u][v], w);
        }
        for(int t = 1;  t <= lim; t++)
        for(int k = 0; k < 9; k++)
            for(int i = 0; i < 9; i++)
                for(int j = 0; j < 9; j++)
                    G[t].dis[i][j] = min(G[t].dis[i][j], G[t].dis[i][k]+G[t].dis[k][j]);
        root = build();
        scanf("%d", &cas);
        while(cas--){
            int st, ed, siz;
            scanf("%d%d%d", &st, &ed, &siz);
            for(int i = 1; i <= siz; i++)
                scanf("%d%d", &q[i].l, &q[i].r);
            sort(q+1, q+1+siz, cmp);
            Maxtri ans = query(q[1].l, q[1].r);
            for(int i = 2; i <= siz; i++){
                ans = merge(ans, query(q[i].l, q[i].r));
            }
            ans.dis[st][ed] < inf ? printf("%d
    ", ans.dis[st][ed]) : puts("-1");
        }
     
    }
    View Code
  • 相关阅读:
    cf1100 F. Ivan and Burgers
    cf 1033 D. Divisors
    LeetCode 17. 电话号码的字母组合
    LeetCode 491. 递增的子序列
    LeetCode 459.重复的子字符串
    LeetCode 504. 七进制数
    LeetCode 3.无重复字符的最长子串
    LeetCode 16.06. 最小差
    LeetCode 77. 组合
    LeetCode 611. 有效三角形个数
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/9275300.html
Copyright © 2011-2022 走看看