Educational Codeforces Round 81 (Rated for Div. 2)(A~D)

A. Display The Number(水題)

分析

分類討論下一下,

代碼

#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <list>
#include <queue>
#include <deque>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
#define ios ios::sync_with_stdio(false) 
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define db double
#define INF 0x3f3f3f3f
#define mod 998244353

const int mxn = 2e5 + 10;
int ar[mxn];


int main()
{
    /* fre(); */
    int T;
    scanf("%d", &T);
    while(T --)
    {
        int n;
        scanf("%d", &n);
        if(n % 2)
        {
            for(int i = 1; i <= n/2; i ++)
            {
                if(i == 1)
                    printf("7");
                else
                    printf("1");

            }
            printf("\n");
        }
        else
        {
            for(int i = 1; i <= n/2; i ++)
            {
                printf("1");

            }
            printf("\n");

        }
    }

    return 0;
}


B. Infinite Prefixes(分類討論?模擬?週期?)

分析

  • 題意
  1. 給我們一個長度爲n的僅由0,1字符組成的字符串aa,將這個字符串無限拼接到一個空串尾部之後形成一個無限序列ss
  2. 定義:關於序列s的中某個位置的前綴差值 pre[i]pre[i]爲1~i之間0字符的數量 - 1字符的數量…
  3. 現在給們一個前綴差值x,問滿足pre[i]==xpre[i]==x的i位置有多少個?
  4. 如果有無限個滿足題意的位置,輸出-1,否則輸出所有滿足題意的位置
  • 分析
  1. 這一題在腦子中想,就被可能的複雜情況給弄暈了,所以我們要選擇分類討論,把複雜的問題化的簡單一點,但是也不能分的太細,否則情況多的自己又迷了,,,要分的有條理,,
  2. 而且s是一個週期循環序列,我們應該儘量 利用它的週期性質,最後就是利用 前綴和 維護數據,
  3. 最後 過程直接看代碼 吧

代碼

#include <bits/stdc++.h>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define db double
#define INF 0x3f3f3f3f
#define mod 998244353

const int mxn = 2e5 + 10;
char ar[mxn];
int pre[mxn];

int main()
{
    /* fre(); */
    int T;
    scanf("%d", &T);
    while(T --)
    {
        int n, x;
        scanf("%d %d", &n, &x);
        scanf("%s", ar + 1);
        for(int i = 1; i <= n; i ++)
        {
            pre[i] = pre[i - 1];
            if(ar[i] == '0') pre[i] ++; 
            else             pre[i] --;
        }

        int all = pre[n];               //週期增量
        int ans = 0;
        if(x == 0) ans ++;              //空串肯定滿足答案
        if(all == 0)
        {
            if(x == 0)                  //一個週期至少一個,有無窮個週期,所以無窮個
            {
                printf("-1\n");
                continue;
            }

            for(int i = 1; i <= n; i ++)
            {
                if(pre[i] == x)
                {
                    ans ++;
                    break;
                }
            }
            if(ans)                     //如果ans>0表示每個週期至少有1個答案,無數個週期無數個答案
                printf("-1\n");
            else
                printf("0\n");
        }
        else			//如果週期增量all != 0
        {
            for(int i = 1; i <= n; i ++)
            {
                if((x - pre[i]) % all == 0 && (x - pre[i]) / all >= 0)
                    ans ++;
            }
            printf("%d\n", ans);
        }
    }



    return 0;
}

C. Obtain The String(暴力模擬+貪心)

分析

  • 題意
  1. 給我們兩個字符串s、t,對於每次操作我們都可以從s中選擇一個子序列把它拼接到一個空串到尾部,問經過一些合理次數的這樣操作,會產生一個新的子串a,能否通過合理的操作之後使 a與t相同,如果可以的話,最少需要多少次這樣的操作?,如果不能輸出-1
  • 分析
  1. 首先判斷 t中的字符是否都在s中出現了,之後都出現了才能通過一定次數的操作拼接出t
  2. 我們思路是,模擬 每次操作從s中合理選擇子序列的過程,在模擬的過程中統計一下操作次數,而且在 某次操作過程中我們應該選擇儘可能多的字符從s中(這樣好耗費的次數纔可能更少)
  3. 對於這個模擬的過程我們要注意,假如我們在s中某個位置(設置個位置爲i)選擇字符之後,下次我們再次進行選擇字符的時候,只能在i位置之後的位置字符中挑選合適的字符,而這個找 i位置之後的位置 的這個過程 則是通過 二分 來快速確定下一個位置的,,,
  4. 主要思路就是這,剩下的看代碼

代碼

#include <bits/stdc++.h>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define db double
#define INF 0x3f3f3f3f
#define mod 998244353

const int mxn = 2e5 + 10;
vector<int> v[26];
int p[26];

void init()
{
    for(int i = 0; i < 26; i ++)
        v[i].clear();
    fill(p, p + 26, 0);
}

int main()
{
    /* fre(); */
    int T;
    scanf("%d", &T);
    while(T --)
    {
        init();
        string  s, t;
        cin >> s >> t;
        for(int i = 0; i < s.size(); i ++)
            v[s[i] - 'a'].pb(i) ;
        int fg = 1;
        for(auto x : t)
        {
            if(v[x - 'a'].size() == 0)
            {
                fg = 0; break;
            }
        }

        if(! fg)
            printf("-1\n");
        else
        {
            int ct = 0;
            for(int i = 0; i < t.size(); )
            {
                int last = -1;

                int pos = upper_bound(v[t[i] - 'a'].begin(), v[t[i] - 'a'].end(), last) - v[t[i] - 'a'].begin();
                while(pos != v[t[i] - 'a'].size() && i < t.size())
                {
                    last = v[t[i] - 'a'][pos];
                    p[t[i] - 'a'] = pos + 1;
                    i ++;
                    if(i >= t.size()) break;
                    pos = upper_bound(v[t[i] - 'a'].begin() + p[t[i] - 'a'], v[t[i] - 'a'].end(), last) - v[t[i] - 'a'].begin();
                }
                ct ++;
                fill(p, p + 26, 0);
            }
            printf("%d\n", ct);
        }
    }

    return 0;
}

D. Same GCDs(歐拉函數+gcd性質應用)

分析

  • 題意
  1. 給我們a、m、x三個變量(1<=a<=m<=1e101<=a<=m<=1e10、0<=x < m請注意x的取值範圍標紅的的部分,這個不是偶然,是有作用的,後面會分析到),
  2. 又給我們一個等式gcd(a,m)==gcd(a+x,m)gcd(a,m)==gcd(a+x,m),問x的取值有多少個使該等式成立?,,輸出符合題意的x的數量
  • 分析
  1. 首先我們看到數據的取值範圍很大,只要要用O(n1/2)O(n^{1/2})或者O(lg(n))O(lg(n))的算法來解決這個問題,
  2. 接下來是我們對所給的等式的變形:
    1. 根據最大公約數的性質,如果a >=b,那麼gcd(a,b)==gcd(ab,b)gcd(a,b)==gcd(a-b,b),換句話說可以寫成:gcd(a,b)=gcd(a%b,b)gcd(a,b)=gcd(a\%b,b)
    2. 另一個性質:如果gcd(a,b)=dgcd(a,b)=d,則這個等式可以變化爲:gcd(a/d,b/d)=1gcd(a/d,b/d)=1
    3. gcd(a,m)=dgcd(a,m)=d,那麼gcd(a+x,m)=gcd((a+x)%m,m)=dgcd(a+x,m)=gcd((a+x)\%m,m)=d根據性質1),我們接下來根據性質2把等式gcd((a+x)%m,m)=d gcd((a+x)\%m,m)=d~,轉化爲下面等式:gcd[(a+x)%m/d,  m/d]=1gcd[(a+x)\%m/d,~~m/d]=1
    4. 根據這個等式我們可以確定(a+x)%m/d(a+x)\%m/d  m/d~~m/d互爲質數,接下來我們就可以應用 歐拉函數的性質來解題,
    5. 歐拉發現一個快速求nn與位於[0,n)[0,n)之間的數字互爲質數的個數,從歐拉函數這個性質的描述中我們可以發現,這個性質求解的互爲質數數量,是有限制區間的就是 之前藍色字體部分
    6. 那麼要麼要想應用 “歐拉函數的性質” 就要滿足人家的限制條件,還記得在 題意敘述 中特別強調的 x的取值範圍0<=x<m0<=x<m嗎?
      1. 我們考慮gcd(a+x,m)gcd(a+x,m)中,如果a<=a+x<ma<=a+x<m的時候,這個時候(a+x)%m(a+x)\%m的取值區間是不變的所以,這個時候(a+x)%m(a+x)\%m的取值範圍爲[a,m)[a,m);
      2. 如果m<=a+x<a+mm<=a+x< a+m 的時候,但是在根據性質1做變換的之後,(a+x)(a+x)%m的取值區間爲[0,a-1].
      3. 好了我們將1,2步驟中的兩個綠色區間拼湊起來爲[0,a-1]+[a,m)=[0,m),這個最終拼湊出來的區間就正好滿足歐拉函數的性質,,,,同理我們可以推出(a+x)%m/d(a+x)\%m/d的取值區間爲:[0,m/d)[0,m/d),那麼下面之前我們變換出的等式,就可使用“歐拉函數的性質”了gcd[(a+x)%m/d,  m/d]=1gcd[(a+x)\%m/d,~~m/d]=1
  3. 至於怎麼用“歐拉函數的性質”就靠自己學習一下的了,,終於說完了

代碼

#include <bits/stdc++.h>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define db double
#define INF 0x3f3f3f3f
#define mod 998244353

const int mxn = 2e5 + 10;
char ar[mxn];
int pre[mxn];


ll euler(ll n)
{
    ll res = n;
    for(ll i = 2; i * i <= n; i ++)
    {
        if(n % i == 0)
        {
            res = res / i * (i - 1);
            while(n % i == 0)   
                n /= i;
        }
    }
    if(n != 1)
        res = res / n * (n - 1);
    return res;
}

ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }



int main()
{
    /* fre(); */
    int T;
    scanf("%d", &T);
    while(T --)
    {
        ll a, m;
        scanf("%lld %lld", &a, &m);
        ll d = gcd(a, m);
        ll ans = euler(m / d);
        printf("%lld\n", ans);
    }

    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章