题目1:正则问题
首先要掌握两点正则运算的基础知识:①括号代表优先计算,②或符号代表二选一。
首先计算一下样例:
可以发现,我们的计算过程可以构成一棵树:
当我们碰到左括号时,需要向下走一层,先计算下一层的值。
当我们碰到右括号时,代表当前层计算结束,可以返回上一层。
当我们碰到x,代表当前计算的x总数可以加一。
当我们碰到或符号,则取或符号之前长度和或符号之后长度(从或符号到下一个右括号或者终点)的最大值。
#include<iostream>
#include<cstring>
using namespace std;
string str;
int k=0;
int dfs()
{
int res=0;
while(k<str.size())
{
if(str[k]=='(')
{
k++;
res+=dfs();
k++;
}
else if(str[k]==')') break;
else if(str[k]=='x')
{
res++;
k++;
}
else if(str[k]=='|')
{
k++;
res=max(res,dfs());
}
}
return res;
}
int main()
{
cin>>str;
cout<<dfs();
}
题目2:带分数
最暴力的做法是,我们枚举1~9的全排列,然后枚举两个断开的地方,将全排列分成三段,分别是a、b、c。这样的时间复杂度是O(9!*9*)。
#include<iostream>
using namespace std;
int n;
int cnt=0;
bool st[10];
int a[10];
void check()
{
int zheng=0;
for(int i=1;i<=7;i++)
{
zheng=zheng*10+a[i];
if(zheng>=n) break;
int son=0;
for(int j=i+1;j<=8;j++)
{
son=son*10+a[j];
int mother=0;
for(int k=j+1;k<=9;k++) mother=mother*10+a[k];
if(son%mother) continue;
if(zheng+son/mother==n) cnt++;
}
}
}
void dfs(int u)
{
if(u>9)
{
check();
return;
}
for(int i=1;i<=9;i++)
{
if(st[i]) continue;
st[i]=1;
a[u]=i;
dfs(u+1);
st[i]=0;
}
}
int main()
{
scanf("%d",&n);
dfs(1);
cout<<cnt;
}
在此基础上进行优化。我们首先将n=a+b/c转变为cn-ac=b,这样一来,我们只需要进行a、c的全排列,判断b是否合法。这是一个嵌套的bfs。
#include<iostream>
using namespace std;
int n;
int cnt=0;
bool st[10];
typedef long long ll;
bool check(int a,int b,int c)
{
if(!a||!b||!c) return false;
bool temp[10];
for(int i=0;i<=9;i++) temp[i]=st[i];
while(b)
{
int x=b%10;
if(x==0||temp[x]) return false;
temp[x]=1;
b/=10;
}
for(int i=1;i<=9;i++) if(temp[i]==0) return false;
return true;
}
void dfsc(int u,int a,int c)
{
if(u>9) return;
int b=(ll)c*n-(ll)a*c;
if(check(a,b,c)) cnt++;
for(int i=1;i<=9;i++)
{
if(st[i]) continue;
st[i]=1;
dfsc(u+1,a,c*10+i);
st[i]=0;
}
}
void dfsa(int u,int a)
{
if(a>=n) return;
dfsc(u+1,a,0);
for(int i=1;i<=9;i++)
{
if(st[i]) continue;
st[i]=1;
dfsa(u+1,a*10+i);
st[i]=0;
}
}
int main()
{
scanf("%d",&n);
dfsa(1,0);
cout<<cnt;
}
题目3:有序分数
这道题的数据范围很小,可以直接用暴力解法,将所有合法的分数列出来,从大到小排序后输出。
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef pair<int,int> PII;
#define x first
#define y second
vector<PII> a;
int n;
int gcd(int a,int b)
{
if(a%b==0) return b;
else gcd(b,a%b);
}
bool cmp(PII x,PII y)
{
return x.x*y.y<x.y*y.x;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(j>=i)
if(gcd(i,j)==1)
a.push_back({i,j});
}
sort(a.begin(),a.end(),cmp);
for(int i=0;i<a.size();i++) printf("%d/%d\n",a[i].x,a[i].y);
}
这道题的递归解法对应了一个很冷门的知识点——Stern-Brocot Tree。
构建过程如下:
对于a/b和c/d,它的左右子树分别为[a/b,(a+c)/(b+d)]、[(a+c)/(b+d),c/d],左<中<右。
#include<iostream>
int n;
void dfs(int a,int b,int c,int d)
{
if(b+d>n) return;
dfs(a,b,a+c,b+d);
printf("%d/%d\n",a+c,b+d);
dfs(a+c,b+d,c,d);
}
int main()
{
scanf("%d",&n);
printf("%d/%d\n",0,1);
dfs(0,1,1,1);
printf("%d/%d\n",1,1);
}
题目4:约数之和
我们对问题进行一些分析:
通过上述分析,我们就得到了递归的雏形。
ac代码如下:
#include<iostream>
using namespace std;
int a,b;
const int mod=9901;
int qmi(int a,int b)
{
int res=1;
while(b)
{
if(b&1) res*=a,res%=mod;
b=b>>1;
a*=a%mod;
a%=mod;
}
return res%mod;
}
int sum(int p,int k)
{
if(k==0) return 1;
if(k%2) return (1+qmi(p,(k+1)/2))*sum(p,(k-1)/2)%mod;
else return 1+p%mod*sum(p,k-1)%mod;
}
int main()
{
scanf("%d%d",&a,&b);
int res=1;
if(!a)
{
printf("0");
return 0;
}
for(int i=2;i<=a;i++)
{
int s=0;
while(a%i==0)
{
s++;
a/=i;
}
res*=sum(i,s*b)%mod;
res%=mod;
}
printf("%d",res);
}
题目5:分形之城
首先观察图形,可以把图形分成四个象限。
先来看等级1如何变化到等级2。
若将等级1放入等级2的第一象限,需要将等级1顺时针旋转90度,并以y轴为轴进行翻转;
若放入第二象限,则不用进行变换;
若放入第三象限,则不用进行变换;
若放入第四象限,需要将等级1逆时针旋转90度,并以y轴为轴进行翻转。
这里需要注意,把等级1放入到等级2时,坐标原点变换了,所以还需要做一个平移的操作。
等级2变换到等级3也遵循这样的规律。
到这里,我们就已经掌握了分形之城的分形规律了。
然后需要推导出坐标变换的规律:
ac代码如下:
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PLL;
#define x first
#define y second
int T;
PLL get_pos(ll n,ll p)
{
if(n==0) return {0,0};
ll len=1ll<<(n-1);
ll cnt=1ll<<(2*n-2);
PLL pos=get_pos(n-1,p%cnt);
ll x=pos.x,y=pos.y;
int z=p/cnt;
if(z==0) return {-y-len,-x+len};
else if(z==1) return {x+len,y+len};
else if(z==2) return {x+len,y-len};
else return {y-len,x-len};
}
int main()
{
scanf("%d",&T);
while(T--)
{
int n;
ll a,b;
scanf("%d%lld%lld",&n,&a,&b);
PLL posa=get_pos(n,a-1);
PLL posb=get_pos(n,b-1);
double dx=posa.x-posb.x,dy=posa.y-posb.y;
dx*=5,dy*=5;
printf("%.0lf\n",sqrt(dx*dx+dy*dy));
}
}