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(分類討論?模擬?週期?)
分析
- 題意
- 給我們一個長度爲n的僅由0,1字符組成的字符串,將這個字符串無限拼接到一個空串尾部之後形成一個無限序列
- 定義:關於序列s的中某個位置的前綴差值 爲1~i之間0字符的數量 1字符的數量…
- 現在給們一個前綴差值x,問滿足的i位置有多少個?
- 如果有無限個滿足題意的位置,輸出-1,否則輸出所有滿足題意的位置
- 分析
- 這一題在腦子中想,就被可能的複雜情況給弄暈了,所以我們要選擇分類討論,把複雜的問題化的簡單一點,但是也不能分的太細,否則情況多的自己又迷了,,,要分的有條理,,
- 而且s是一個週期循環序列,我們應該儘量 利用它的週期性質,最後就是利用 前綴和 維護數據,
- 最後 過程直接看代碼 吧
代碼
#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(暴力模擬+貪心)
分析
- 題意
- 給我們兩個字符串s、t,對於每次操作我們都可以從s中選擇一個子序列把它拼接到一個空串到尾部,問經過一些合理次數的這樣操作,會產生一個新的子串a,能否通過合理的操作之後使 a與t相同,如果可以的話,最少需要多少次這樣的操作?,如果不能輸出-1
- 分析
- 首先判斷 t中的字符是否都在s中出現了,之後都出現了才能通過一定次數的操作拼接出t
- 我們思路是,模擬 每次操作從s中合理選擇子序列的過程,在模擬的過程中統計一下操作次數,而且在 某次操作過程中我們應該選擇儘可能多的字符從s中(這樣好耗費的次數纔可能更少)
- 對於這個模擬的過程我們要注意,假如我們在s中某個位置(設置個位置爲i)選擇字符之後,下次我們再次進行選擇字符的時候,只能在
i位置之後的位置
字符中挑選合適的字符,而這個找i位置之後的位置
的這個過程 則是通過 二分 來快速確定下一個位置的,,, - 主要思路就是這,剩下的看代碼
代碼
#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性質應用)
分析
- 題意
- 給我們a、m、x三個變量(、0<=
x < m
請注意x的取值範圍標紅的的部分,這個不是偶然,是有作用的,後面會分析到), - 又給我們一個等式,問x的取值有多少個使該等式成立?,,輸出符合題意的x的數量
- 分析
- 首先我們看到數據的取值範圍很大,只要要用或者的算法來解決這個問題,
- 接下來是我們對所給的等式的變形:
- 根據最大公約數的性質,如果a >=b,那麼,換句話說可以寫成:
- 另一個性質:如果,則這個等式可以變化爲:
- 設,那麼(
根據性質1
),我們接下來根據性質2
把等式,轉化爲下面等式: - 根據這個等式我們可以確定與互爲質數,接下來我們就可以應用
歐拉函數的性質
來解題, - 歐拉發現一個快速求與位於之間的數字
互爲質數
的個數,從歐拉函數這個性質的描述中我們可以發現,這個性質求解的互爲質數數量,是有限制區間的就是 之前藍色字體部分, - 那麼要麼要想應用 “歐拉函數的性質” 就要滿足人家的限制條件,還記得在 題意敘述 中特別強調的 x的取值範圍嗎?
- 我們考慮中,如果的時候,這個時候的取值區間是不變的所以,這個時候的取值範圍爲;
- 如果 的時候,但是在根據性質1做變換的之後,的取值區間爲[0,a-1].
- 好了我們將1,2步驟中的兩個綠色區間拼湊起來爲[0,a-1]+[a,m)=[0,m),這個最終拼湊出來的區間就正好滿足歐拉函數的性質,,,,同理我們可以推出的取值區間爲:,那麼下面之前我們變換出的等式,就可使用“歐拉函數的性質”了
- 至於怎麼用“歐拉函數的性質”就靠自己學習一下的了,,
終於說完了
代碼
#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;
}