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;
}