• 2020 hdu contest1 水题


    自我感觉航电的题目极其经典

    Distinct Sub-palindromes

    Problem Description
    S is a string of length n. S consists of lowercase English alphabets.
    Your task is to count the number of different S with the minimum number of distinct sub-palindromes. Sub-palindrome is a palindromic substring.
    Two sub-palindromes u and v are distinct if their lengths are different or for some i (0≤i≤length), ui≠vi. For example, string “aaaa” contains only 4 distinct sub-palindromes which are “a”, “aa”, “aaa” and “aaaa”.
    Input
    The first line contains an integer T (1≤T≤105), denoting the number of test cases.
    The only line of each test case contains an integer n (1≤n≤109).
    Output
    For each test case, output a single line containing the number of different strings with minimum number of distinct sub-palindromes.
    Since the answer can be huge, output it modulo 998244353.
    Sample Input
    2
    1
    2
    Sample Output
    26
    676

    第一个最简单的题目,有多少种可能的字符串里面包含的回文串最小,枚举一下发现,n = 1的时候,回文串的数量是1,有26种字符串,n = 2 , 3的时候,不管有几个字母 是相同,回文串的数量都是3,当n大于3的时候,我们也可以构造出只有3个回文串的字符串,只要abcabcabc的构造就行了, 这个有26 * 25 * 24个

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <unordered_map>
    #include <vector>
    #include <map>
    #include <list>
    #include <queue>
    #include <cstring>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    #include <stack>
    #include <set>
    #pragma GCC optimize(3 , "Ofast" , "inline")
    using namespace std ;
    #define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
    #define x first
    #define y second
    #define ls rt << 1
    #define rs rt << 1 | 1
    typedef long long ll ;
    const double esp = 1e-6 , pi = acos(-1) ;
    typedef pair<int , int> PII ;
    const int N = 1e6 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
    int cinint(){  int t ; scanf("%d" , &t) ;  return t ;}
    int cinll(){ll t ;scanf("%lld" , &t) ;return t ;}
    int work()
    {
      int n = cinint() ;
      if(n <= 3) {
        int res = 1 ;
        while(n) n -- , res *= 26 ;
        printf("%d
    " , res) ;
      }
      else printf("%d
    " , 26 * 25 * 24) ;
      return 0 ;
    }
    int main()
    {
      int t = cinint() ;
      while(t --)
      work() ;
      return 0 ;
    }
    /*
    */
    

    Fibonacci Sum

    在这里插入图片描述
    在这里插入图片描述

    Since the answer can be huge, output it modulo 1000000009 (109+9).

    求解这个公式

    写在这个地方,纪念第一次遇到这种题目
    斐波拉契数列的通项公式:

    [f[i] = af[i - 1] + b * f[i - 2] \ f[n] = frac{k^n*(f[1]-m*f[0]) - m^n*(f[1] -k* f[0])}{k - m} \ m = frac{a +sqrt{a^2+4b}}{2} \ k = frac{a -sqrt{a^2+4b}}{2} ]

    由此得出当前公式的斐波拉契数列通项公式

    [f_n = frac{1}{sqrt5} * {{(frac{1 + sqrt5}{2}) ^ n - (frac{1 - sqrt5}{2})^n}} \ f_0 = 0 , f_1 = 1 ]

    在模意义下,(sqrt5)是可以求出来的,根据二次剩余定理(x^2 =5 \% mod)

    template<typename T>
    inline int pow(int x,T y)
    {
        rg int res=1;x%=mod;
        for(;y;y>>=1,x=(ll)x*x%mod)if(y&1)res=(ll)res*x%mod;
        return res;
    }
    inline int Quadratic_residue(const int a)
    {
    	if(a==0)return 0;
    	int b=(rand()<<14^rand())%mod;
    	while(pow(b,(mod-1)>>1)!=mod-1)b=(rand()<<14^rand())%mod;
    	int s=mod-1,t=0,x,inv=pow(a,mod-2),f=1;
    	while(!(s&1))s>>=1,t++,f<<=1;
    	t--,x=pow(a,(s+1)>>1),f>>=1;
    	while(t)
    	{
    		f>>=1;
    		if(pow((int)((ll)inv*x%mod*x%mod),f)!=1)x=(ll)x*pow(b,s)%mod;
    		t--,s<<=1;
    	}
    	return min(x,mod-x);
    }
    
    

    先把 (sqrt5) 求解出来之后,剩下的都可以用费马小定理求解在模意义下的逆元,D = (frac{1}{sqrt5} \% mod) , A = (frac{1 + sqrt5}{2}\%mod) , B = (frac{1 - sqrt5}{2}\%mod)

    [f_n ^k= D ^ k * (A^n - B ^n)^k ]

    下面就是新学到的小技巧,虽然高中都学过,经常用,但是这个时候却想不起来,太失败了:后面是一个二项式,直接展开

    [f_n^k = D^k*[C_k^0 * (A^n)^k * (B^n)^0*(-1)^0 +C_k^1 * (A^n)^{k -1} * (B^n)^1*(-1)^1 + ......+ C_k^k * (A^n)^0 * (B^n)^k*(-1)^k] ]

    [f_{2n}^k = D^k*[C_k^0 * (A^{2n})^k * (B^{2n})^0*(-1)^0 +C_k^1 * (A^{2n})^{k -1} * (B^{2n})^1*(-1)^1 + ......+ C_k^k * (A^{2n})^0 * (B^{2n})^k*(-1)^k] ]

    [=D^k*[C_k^0 * (A^n)^{2k} * (B^n)^{2*0}*(-1)^0 +C_k^1 * (A^n)^{2(k -1)} * (B^n)^2*(-1)^1 + ......+ C_k^k * (A^n)^{2*0} * (B^n)^{2k}*(-1)^k] ]

    [f_{3n}^k = D^k*[C_k^0 * (A^{n})^{3 * k} * (B^{n})^0*(-1)^{3 * 0} +C_k^1 * (A^{n})^{3(k -1)} * (B^{n})^3*(-1)^1 + ......+ C_k^k * (A^{n})^{3 * 0} * (B^{n})^{3 * k}*(-1)^k] ]

    优化:

    1. 发现(D^k) 这个系数不论n为多少,都不变,所以我们最后乘一下就行
    2. 枚举(C_k^r) , 那么对于同一个r而言,(f_c+f_{2c}+....+f_{nc})其中(C_k^r)项的贡献是一个等数列,首项和公比都是 (q = (A^n)^{k - r} * (B^n)^{r}) , 并且从枚举r到枚举r + 1 , 公比q的变化为 (q = frac{q * B^n}{(A^n)}) , 与处理一下就行了。
    3. 还要特判公比q = 1的情况,此时 (f_c+f_{2c}+....+f_{nc})其中(C_k^r)项的贡献是 n
    
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <unordered_map>
    #include <vector>
    #include <map>
    #include <list>
    #include <queue>
    #include <cstring>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    #include <stack>
    #include <set>
    #pragma GCC optimize(3 , "Ofast" , "inline")
    using namespace std ;
    #define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
    #define x first
    #define y second
    #define ls rt << 1
    #define rs rt << 1 | 1
    typedef long long ll ;
    const double esp = 1e-6 , pi = acos(-1) ;
    typedef pair<int , int> PII ;
    const int N = 1e5 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 9;
    ll D , A , B ;
    inline ll qmi(ll a , ll b){
      ll res = 1 ;
      a %= mod ;
      if(b > mod) b = b % (mod - 1) + mod - 1 ;
      while(b) {
        if(b & 1) res = res * a % mod ;
        a = a * a % mod ;
        b >>= 1 ;
      }
      return res ;
    }
    ll inv[N] , f[N] ;
    inline void init(){
      f[0] = 1 ;
      for(int i = 1; i < N ;i ++ )
       f[i] = f[i - 1] * i % mod ;
      inv[N - 1] = qmi(f[N - 1] , mod - 2) ;
      for(int i = N - 2; i >= 0 ;i --)
       inv[i] = 1ll * inv[i + 1] * (i + 1) % mod ;
      return ;
    }
    inline ll C(int n , int m)
    {
      return f[n] * inv[m] % mod * inv[n - m] % mod ;
    }
    inline ll in(){
      ll x = 0 , f = 1;
      char c = getchar() ;
      while(c > '9' || c < '0')
       {
         if(c == '-') f = -1 ;
         c = getchar() ;
       }
       while(isdigit(c)) x = x * 10 + c - 48 , c = getchar() ;
       return x * f ;
    }
    int main()
    {
      init() ;
      D = 276601605 ;
      A = 691504013 ;
      B = 308495997 ;
      int t = in() ;
      while(t --)
       {
         ll n = in() , c = in() ,  k = in() ;
    
         ll ans = 0 ;
         ll a = qmi(A , c) , b = qmi(B , c) ;
         ll r1 = qmi(a , k) , r2 = 1 ;
         ll temp1 = qmi(a , mod - 2) ;
         for(int r = 0 ;r <= k ; r ++ ) {
           ll q = r1 * r2 % mod , temp ;
           if(q == 1) {
             temp = n % mod ;
           }
           else temp = q * (qmi(q , n) - 1) % mod * qmi(q - 1 , mod - 2) % mod ;
           temp = 1ll * temp * C(k , r) % mod ;
           if(r % 2) ans -= temp ;
           else ans += temp ;
           ans = (ans % mod + mod) % mod ;
           r1 = r1 * temp1 % mod ;
           r2 = r2 * b % mod ;
         }
         ans = ans * qmi(D , k) % mod ;
         printf("%lld
    " , ans) ;
       }
      return 0 ;
    }
    /*
    */
    
    

    Finding a MEX

    Problem Description
    Given an undirected graph G=(V,E). All vertices are numbered from 1 to N. And every vertex u has a value of Au. Let Su={Av│(u,v)∈E}. Also, F(u) equals MEX(minimum excludant) value of Su. A MEX value of a set is the smallest non-negative integer which doesn’t exist in the set.
    There are two types of queries.
    Type 1: 1 u x – Change Au to x (0≤x≤109).
    Type 2: 2 u – Calculate the value of F(u).
    For each query of type 2, you should answer the query.
    Input
    The first line of input contains a single integer T (1≤T≤10) denoting the number of test cases. Each test case begins with a single line containing two integers n (1≤n≤105), m (1≤m≤105) denoting the number of vertices and number of edges in the given graph.
    The next line contains n integers and ith of them is a value of Ai (0≤Ai≤109).
    The next m lines contain edges of the graph. Every line contains two integers u, v meaning there exist an edge between vertex u and v.
    The next line contains a single integer q (1≤q≤105) denoting the number of queries.
    The next q lines contain queries described in the description.
    Output
    For each query of type 2, output the value of F(u) in a single line.
    Sample Input
    1
    5 4
    0 1 2 0 1
    1 2
    1 3
    2 4
    2 5
    5
    2 2
    1 2 2
    2 2
    1 3 1
    2 1
    Sample Output
    2
    2
    0

    1. 首先对于一个维护mex值,可以直接for循环扫一遍,或者用权值线段树或者树状数组加二分查询,如果数据小的话,就可以直接用for循环扫一遍,数据大的话,需要树状数组加二分了
    2. 对于一点图里面的点而言,如果它的邻接点而言,如果数量很少,就可以直接使用第一种情况求mex,否则的话,需要第二种情况求mex
    3. 在本题,取(sqrt{n})为数据大小的分界点
    4. 如果一个点u的度数为d[u] , 那么他的mex值最多最多只有d[u] 个, 0 , 1 , 2 , 3 , 4 5.。。。。d[u] , 所以只要在求解mex的时候,碰到点的权值(a[u] >= d[u]) , 那么这点可以不做处理。
    5. 对于本题种第一种方法求解mex,直接扫一遍临点即可。
    6. 对于第二种方法,用树状数组的话,将每个大节点建立一个树状数组,不过空间要求下, 需要动态开点,用个vector动态开点即可, 将a[x] = w , 只需要先删除这个a[x] , 然后再插入w, 更新对临点的影响, 在临点的树状数组上面操作,查询的话就二分查找一下即可

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <unordered_map>
    #include <vector>
    #include <map>
    #include <list>
    #include <queue>
    #include <cstring>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    #include <stack>
    #include <set>
    #include <deque>
    #pragma GCC optimize(3 , "Ofast" , "inline")
    using namespace std ;
    #define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
    #define x first
    #define y second
    #define ls rt << 1
    #define rs rt << 1 | 1
    typedef long long ll ;
    const double esp = 1e-6 , pi = acos(-1) ;
    typedef pair<int , int> PII ;
    const int N = 1e6 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
    vector<int> v[N] ;
    vector<int> nb[350] , bt[350] , mx[N] ;
    int a[N] , n , m ;
    int d[N] , limit ;
    int size[N] , idx[N] , cnt ;
    bool vis[350] ;
    int lowbit(int x)
    {
      return x & -x ;
    }
    void add(int t , int x , int k)
    {
      while(x <= size[t])
       bt[t][x] += k , x += lowbit(x) ;
      return ;
    }
    int ask(int x , int y)
    {
      int res = 0 ;
      while(y)
       res += bt[x][y] , y -= lowbit(y) ;
      return res ;
    }
    void calc(int x , int w)
    {
    
      for(auto v : mx[x]){
        int id = idx[v] ;
        if(a[x] <= d[v]) {
          nb[id][a[x]] -- ;
          if(!nb[id][a[x]] && a[x])
           add(id , a[x] , -1) ;
        }
        if(w <= d[v])
         {
           nb[id][w] ++ ;
           if(nb[id][w] == 1 && w)
            add(id , w , 1) ;
         }
      }
      a[x] = w ;
      return ;
    }
    int ask_big(int x)
    {
      if(!nb[idx[x]][0]) return 0 ;
      int l = 0 , r = size[idx[x]] ;
      int mex = size[idx[x]] ;
      while(l <= r)
       {
         int mid = l + r >> 1 ;
         if(ask(idx[x] , mid) < mid) mex = mid , r = mid - 1 ;
         else l = mid + 1 ;
       }
       return mex ;
    }
    int ask_small(int u)
    {
      for(int i = 0 ;i <= d[u] ;i ++ )
       vis[i] = false ;
      for(auto x : v[u])
       if(a[x] <= d[u])
        vis[a[x]] = true ;
      for(int i = 0 ;i <= d[u] ;i ++ )
       if(!vis[i])
        return i ;
    
    }
    int work()
    {
      scanf("%d%d" , &n , &m) ;
      for(int i = 0 ;i <= n ;i ++ ) v[i].clear() , mx[i].clear() , d[i] = 0;
      for(int i = 1; i <= n ;i ++ ) scanf("%d" , &a[i]) ;
      for(int i = 1; i <= m ;i ++ )
       {
         int a , b ;
         scanf("%d%d" , &a , &b) ;
         v[a].push_back(b) , v[b].push_back(a) ;
         d[a] ++ , d[b] ++ ;
       }
      cnt = 0 ;
      limit = sqrt(n) ;
      for(int i = 1; i <= n ;i ++ )
       {
         if(d[i] < limit) continue ;
         idx[i] = ++ cnt ;
         size[cnt] = d[i] ;
         bt[cnt].resize(d[i] + 5) ;
         nb[cnt].resize(d[i] + 5) ;
         for(int j = 0 ;j <= d[i] ;j ++ )
          bt[cnt][j] = nb[cnt][j] = 0 ;
         for(auto x : v[i])
          {
            if(a[x] > d[i]) continue ;
            nb[cnt][a[x]] ++ ;
            if(nb[cnt][a[x]] == 1 && a[x])
             add(cnt , a[x] , 1) ;
          }
       }
       for(int i = 1; i <= n ;i ++ )
        for(auto x : v[i])
         if(d[x] >= limit)
          mx[i].push_back(x) ;
    
        int q ;
        scanf("%d" , &q) ;
        while(q --) {
          int op , x , y ;
          scanf("%d%d" , &op , &x) ;
          if(op == 1) scanf("%d" , &y) , calc(x , y) ;
          else {
            if(d[x] >= limit)
             printf("%d
    " , ask_big(x)) ;
             else printf("%d
    " , ask_small(x)) ;
          }
        }
      return 0 ;
    }
    int main()
    {
      int t ;
      scanf("%d" , &t) ;
      while(t --)
      work() ;
      return 0 ;
    }
    /*
    */
    

    Leading Robots

    Problem Description
    Sandy likes to play with robots. He is going to organize a running competition between his robots. And he is going to give some presents to the winners. Robots are arranged in a line. They have their initial position (distance from the start line) and acceleration speed. These values might be different. When the competition starts, all robots move to the right with speed:
    Here a is acceleration speed and t is time from starting moment.
    Now, the problem is that, how many robots can be the leader from the starting moment?
    Here leader means the unique rightmost robot from the start line at some moment. That is, at some specific time, if a robot is rightmost and unique then it is the leading robot at that time. There can be robots with same initial position and same acceleration speed.
    The runway is so long that you can assume there's no finish line.
    Input
    The input consists of several test cases. The first line of input consists of an integer T(1≤ T≤50), indicating the number of test cases. The first line of each test case consists of an integer N(0 < N≤ 50000), indicating the number of robots. Each of the following N lines consist of two integers: p,a (0 < p,a < 231) indicating a robot's position and its acceleration speed.
    Output
    For each test case, output the number of possible leading robots on a separate line.
    Sample Input
    1
    3
    1 1
    2 3
    3 2
    Sample Output
    2

    根据物理学公式

    [x = x_0 + frac{at^2}{2} ]

    , 转化为

    [y = k * x + b ]

    [b = 2 * x_0 ]

    [k = a ]

    题目要求有多少种情况有一个人领先,看这写直线组成的直线图
    在这里插入图片描述
    题目也就是要求有多少直线在最上面,可以发现

    1. 如果当前直线的斜率和初始位置都大于另一条直线,那么肯定选当前直线
    2. 如果当前直线存在重复的几条,那么肯定没戏
      在这里插入图片描述
    3. 对于排除上面两个条件,基本上就只剩下上图中的关系,黑色的线是两种情况,蓝色和红色是固定的,那么总共两种情况,可以发现对于2号黑色的线来说,三条线都有可能,但是对于1号线来说,红色的线完全没戏。
      4.怎么判断1号线和2号线呢,用一个栈维护,首先排掉前两种条件,然后看两条黑色线的与蓝色与红色线的交点即可
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <unordered_map>
    #include <vector>
    #include <map>
    #include <list>
    #include <queue>
    #include <cstring>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    #include <stack>
    #include <set>
    #include <deque>
    #pragma GCC optimize(3 , "Ofast" , "inline")
    using namespace std ;
    #define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
    #define x first
    #define y second
    #define ls rt << 1
    #define rs rt << 1 | 1
    typedef long long ll ;
    const double esp = 1e-6 , pi = acos(-1) ;
    typedef pair<ll , ll> PII ;
    const ll N = 1e6 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
    PII a[N] , b[N] ;
    ll st[N] , vis[N] , len , top , res[N] ;
    bool check(PII a , PII b , PII c)
    {
      return (a.y - b.y) * (c.x - a.x) >= (a.y - c.y) * (b.x - a.x) ;
    }
    int work()
    {
      ll n ;
      scanf("%lld" , &n) ;
      for(ll i = 1; i <= n ;i ++ ) scanf("%lld%lld" , &a[i].y ,&a[i].x) , a[i].y *= 2 , vis[i] = 0 , res[i] = 0 ;
      sort(a + 1 , a + n + 1) ;
      len = 0 , top = 0 ;
      for(ll i = 1 , r = 1 ; r <= n ;i = ++ r ) {
        while(r < n && a[i] == a[r + 1]) r ++ ;
        b[++ len] = a[r] ;
        if(i != r) vis[len] = 1 ;
      }
    
      for(ll i = 1 , r = 1 ; r <= len ;i = ++ r )
       {
         while(r < len && b[i].x == b[r + 1].x) r ++ ;
         i = r ;
         while(top && b[i].y >= b[st[top]].y) -- top ;
         while(top > 1 && check(b[st[top - 1]] ,b[st[top]] , b[i])) -- top ;
         st[++ top] = i ;
       }
      for(ll i = 1; i <= top ;i ++ ) res[st[i]] = 1 ;
      ll ans = 0 ;
      for(ll i = 1 ;i <= len ;i ++ )
       if(res[i] && !vis[i]) ++ ans ;
      cout << ans << endl ;
      return 0 ;
    }
    int main()
    {
      int t ;
      scanf("%d" , &t) ;
      while(t --)
      work() ;
      return 0 ;
    }
    /*
    5
    5
    18859 15506
    13613 8023
    19732 1693
    15221 15234
    22222 3326
    */
    
    
  • 相关阅读:
    大数据并发控制思考
    同步和异步的区别
    java枚举使用详解
    利用反射实现动态方法调用
    利用反射查看类的声明信息
    用两个栈实现对列
    c标签 if else c标签 总结
    struts2标签获取parameter,request,session,application中的值
    mysql日期加减
    详细介绍Java中的堆、栈和常量池
  • 原文地址:https://www.cnblogs.com/spnooyseed/p/13371389.html
Copyright © 2020-2023  润新知