C 题(暴力枚举,next_permutation的使用简化搜索的代码)
题意:
n 长的字符串,求这个字符串的排列中,不存在k 长的回文子串的,排列有多少种。
可以看到 n 最大只有 10 ,所以可以直接暴力。使用next_permutation 之后,代码就十分美丽了。(记得先sort ,之后才能使用 ~~)
#include <bits/stdc++.h>
using namespace std;
void solve()
{
int n,k;cin>>n>>k;
string s;cin>>s;
sort(s.begin(),s.end());
int ans=0;
do
{
bool flag=true;//假设这个排列 符合条件
//枚举 长度为k的 起点
for (int i=0;i<=n-k;i++)
{
bool f=true;//当前枚举的子串是回文
//j 代表偏移量
for(int j=0;j<k-1-j;j++)
{
if (s[i+j]!=s[i+k-1-j]){
f=false;break;
}
}
if (f){
flag=false;
break;
}
}
if (flag)ans++;
} while (next_permutation(s.begin(),s.end()) );
cout<<ans<<"\n";
}
int main()
{
std::cin.tie(nullptr)->sync_with_stdio(false);
int t; t=1;
//cin>>t;
while(t--)
{
solve();
}
return 0;
}
D题:
问 第n 个回文数 ,是多少。
0 是第一个回文数。
分析:
因为回文数两边是对称的,所以我们只用考虑一半就可以了。
两位 的回文数 有 9种
三位 910 _ _
四位 910 _ _
五位 91010 _ _ _
我们可以发现 对于 长度为l 的回文数,有 k=(L+1)>>1 9*10^(k-1) 种结果。
我们先确定 第N 个回文数,有几位。
这个可以给 n 不断减去 两位 的个数,三位的个数。知道减不了为止。此时的L 就是 长度,这个时候 n 剩余的数,代表着 我们要寻找的,是长度为l 的的第 n 个。 左半边的数字就是 (10^(k-1)+(n-1))
当然因为有0 的存在,我们先对N 处理一下。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int a[10000];
ll pow(ll a,ll b)
{
ll ans=1;
while(b)
{
if (b&1){
ans=ans*a;
}
a=a*a;
b>>=1;
}
return ans;
}
void solve()
{
ll n;cin>>n;
n--;
if (n<10){
cout<<n<<"\n";
return;
}
int l=1;// 确定 第N个回文数的 位数
while(1)
{
//这是 对称轴 的位置
int t=(l+1)>>1;
ll m=9ll*pow(10,t-1);
if (n>m)n-=m;
else break;
l++;
}
// 此时 的 n 是 有 l 位 的第 n 个回文数
// 对称轴 左边的数字 应该是 10^(k-1)+n-1
//因为100000 是第一大的
//记得判断 对称轴
int t=(l+1)>>1;
int len=0;
n-=1;
while(n)a[++len]=n%10,n/=10;
a[t]+=1;
for (int i=t;i;i--){
cout<<a[i];
}
for(int i=1+(l&1);i<=t;i++){
cout<<a[i];
}
cout<<"\n";
}
int main()
{
std::cin.tie(nullptr)->sync_with_stdio(false);
int t; t=1;
//cin>>t;
while(t--)
{
solve();
}
return 0;
}