思路:
- 我们从低位凑到高位,因为尽可能unlucky,所以我们保证凑的数字是相同的如1111,4444等(每次前i位相同,其余位数不变)
- 只要我们当前凑的这个数字符合范围,显然可以推出最优解
- 注意,我们需要同时从上限r与下限l开始凑,如37与42,如果只凑l,只能凑37,38,39(凑的都是个位数),再凑r(能凑40,41,42)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
#define int long long
#define endll endl<<endl
typedef unsigned long long ull;
typedef pair<long long, long long> pll;
//---------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------//
const int INF = 0x3f3f3f3f; //int型的INF
const ll llINF = 0x3f3f3f3f3f3f3f3f;//ll型的llINF
const int N = 2e5 + 10;
int check(int x)
{
set<int>s;
while (x)
{
s.insert(x%10);
x/=10;
}
return (*s.rbegin()-*s.begin());
}
void mysolve()
{
ll l,r;
cin>>l>>r;
ll ans=l,p=1;
for (int i=1; i<=19; ++i)
{
for (int x=0; x<10; ++x)
{
int tmp=l/p*p+(p-1)/9*x;//l/p*p是先使前面i位变为0,再用(p-1)/9*x保证前面i位是相同的
if (tmp>=l&&tmp<=r&&check(tmp)<check(ans))ans=tmp;
tmp=r/p*p+(p-1)/9*x;
if (tmp>=l&&tmp<=r&&check(tmp)<check(ans))ans=tmp;
}
p*=10;
}
cout<<ans<<endl;
}
int32_t main()
{
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll t;
cin >> t;
while (t--)
{
mysolve();
}
system("pause");
return 0;
}
思路:
- 要算多少个不匹配需要变化,有亿点困难。我们反过来想,需要的最大操作次数是ans=
- 如果我们对于位置i数a[i],前面每有一个与它匹配的数,那就ans-1。所以我们可以对于每个数,寻找它前面是不是有在k范围内与它对称的数(且这两个数所属的k区间合法,即区间[l,r],l>=1,r<=n),有就减一
- 因此,我们只需要把每个数出现的位置存下来,即v[val]存储的是出现值为val的所有位置。
- 当然,你肯定会注意到这样存,有可能两个数之间是不匹配的,注意题目说的k为奇数,发现匹配的数奇偶性一定相同,所以我们改为v[val][i],奇偶性分开存储就可。
- 最后处理就是合法区间了,我们设t在i左边并且与它对称。首先,t>=1,还有区间中点必须左右都有长度为k/2的区间,不够就不合法,即与,最后还有t<=i-2(k=1直接0返回,我们讨论k至少为3)。还有t>=i-k+1,那么我们就可以求出t所属区间[l,r]有多少个符合情况的数
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define int ll
const int N = 2e5 + 10;
vector<int>a[N][2];
int32_t main()
{
int n,k,x,maxn=-1;
cin>>n>>k;
for (int i=1; i<=n; ++i)
{
cin>>x;
maxn=max(maxn,x);
a[x][i&1].push_back(i);//分奇偶性存入
}
if (k==1)//k=1不需处理
{
cout<<0<<endl;
return 0;
}
ll ans=(n-k+1)*(k/2);//最多处理次数
for (int i=1; i<=maxn; ++i)for (int j=0; j<2; ++j)
{
for (auto &x:a[i][j])
{
int l=max({1ll,x-k+1,2+k/2*2-x});//每次寻找出现在x之前的值为i的符合区间的数
int r=min(x-2,2*n-x-k/2*2);
if (l<=r)
{
ans-=upper_bound(a[i][j].begin(),a[i][j].end(),r)-lower_bound(a[i][j].begin(),a[i][j].end(),l);//合法区间里面存在的数个数
}
}
}
cout<<ans<<endl;
}
思路:
- 一个串,只要存在一个数(多个数)合法就合法,但是全部不合法才不合法)显然讨论不合法情况比较简单。
- 假设x符合情况,那么假设sum为所有数和,设x符合,那么有x≡sum-x(mod m),即2x≡sum(mod m)
- 因为组合情况就是每一位选0~k直接的一个数,我们任意想到背包问题,用dp[i][j]表示当前第i为(要求求取l前面i-1位的所有情况)和为j的不合法情况总数(选不合法,我们只需要保证每一位取的x不合法即可)。
- 因为sum有k种情况,那么我们枚举所有sum的情况,求出相应sum的不合法个数,然后在求当前sum时每一位选取的数x不满足2*x≡sum(mod m)即可。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define int ll
const int N = 110;
int n,k,mod;
ll dp[N][40];
ll qpow(ll base,ll power)
{
ll ans=1;
while (power)
{
if (power&1)ans=ans*base%mod;
power>>=1,base=base*base%mod;
}
return ans;
}
ll tosum(int sum)//求取n位和为sum的不合法数
{
memset(dp,0,sizeof(dp));
dp[0][0]=1;//这是为了赋值每一位dp[1][j],显然一位数时,不合法情况有k-1种
for (int i=1; i<=n; ++i)for (int x=0; x<k; ++x)if (x*2%k!=sum)//转移式是处理了i-1个数,当前第i为选x(它不合法),更新这i位一共和为h的情况
{
for (int h=0; h<k; ++h)dp[i][h]=(dp[i][h]+dp[i-1][(k+h-x)%k])%mod;
}
return dp[n][sum];
}
int32_t main()
{
cin>>n>>k>>mod;
ll ans=qpow(k,n);//情况总数
for (int i=0; i<k; ++i)ans=(ans+mod-tosum(i))%mod;//枚举sum减去不合法总数
cout<<ans<<endl;
return 0;
}