A:
解:
暴力。假设
A
,
B
A,B
A,B分别是下标为奇数和偶数的序列。找出每个序列中出现次数最多。
然后用
n
n
n减去次数之和。
但是题目规定这两个序列的数不能一样,所以需要特判一下。
附上本蒟蒻十分丑陋的代码
#include<bits/stdc++.h>
using namespace std;
int n;
const int maxn=1e5+5;
typedef pair<int,int> P;
#define x first
#define y second
P a1[maxn],a2[maxn];
int main()
{
cin>>n;
int a;
for(int i=1;i<=n;i++)
{
cin>>a;
if(i&1)
{
a1[a].x++;
a1[a].y=a;
}
else
{
a2[a].x++;
a2[a].y=a;
}
}
sort(a1+1,a1+maxn-4,greater<P>() );
sort(a2+1,a2+maxn-4,greater<P>() );
if(a1[1].y!=a2[1].y)cout<<n-a1[1].x-a2[1].x;
else cout<<n-max(a1[2].x+a2[1].x,a1[1].x+a2[2].x);
return 0;
}
B:
解:
我们知道使
∑
i
=
1
n
∣
a
i
−
x
∣
\sum_{i=1}^{n}|a_i-x|
∑i=1n∣ai−x∣最小的
x
x
x是序列
{
a
i
}
\{a_i\}
{ai}的中位数。
这题要求的是
∑
i
=
1
n
∣
a
i
−
(
x
+
i
)
∣
\sum_{i=1}^n|a_i-(x+i)|
∑i=1n∣ai−(x+i)∣的最小值。
我们立即注意到:
设
b
i
=
a
i
−
i
b_i=a_i-i
bi=ai−i
则原式为:
∑
i
=
1
n
∣
b
i
−
x
∣
\sum_{i=1}^n|b_i-x|
∑i=1n∣bi−x∣
所以
x
x
x为序列
{
b
i
}
\{b_i\}
{bi}的中位数
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
typedef long long ll;
ll sum;
ll a[maxn];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
a[i]-=i;
}
sort(a+1,a+1+n);
ll x;
if(n&1)x=a[n/2+1];
else x=(a[n/2]+a[n/2+1])/2;
for(int i=1;i<=n;i++)sum+=abs(a[i]-x);
cout<<sum;
return 0;
}
c
解:
这道很显然是求对于一个数
x
x
x,在
[
1
,
x
−
1
]
[1,x-1]
[1,x−1]中有多少数是与它不互质的。
[
1
,
x
−
1
]
[1,x-1]
[1,x−1]中与
x
x
x互质的数的个数是
φ
(
x
)
\varphi(x)
φ(x)
a
n
s
=
x
−
1
−
φ
(
x
)
ans=x-1-\varphi(x)
ans=x−1−φ(x)
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int maxn=10000000+5;
int phi[maxn];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)phi[i]=i;
for(int i=2;i<=n;i++)
{
if(phi[i]==i)
{
for(int j=i;j<=n;j+=i)
phi[j]=phi[j]/i*(i-1);
}
}
int x;
for(int i=1;i<=m;i++)
{
cin>>x;
cout<<x-1-phi[x]<<" ";
}
return 0;
}
D:
解:
把箭的颜色当做模板,把怪兽的颜色当做文本。
那么第一个问题就是就模板在文本中最大的匹配长度。
很自然地就想到了
K
M
P
KMP
KMP
一边匹配一边记录最大的匹配长度。
第二个问题在记录匹配长度的时候就可以用前缀和算出。
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int maxn=20000+5;
char A[maxn],B[maxn];
int fail[maxn];
int w[maxn];
int cnt=0,ans;
void kmp()
{
int j=0;
for(int i=2;i<=n;i++)
{
while(j&&B[j+1]!=B[i])j=fail[j];
if(B[j+1]==B[i])j++;
fail[i]=j;
}
j=0;
for(int i=1;i<=m;i++)
{
while(j&&B[j+1]!=A[i])j=fail[j];
if(B[j+1]==A[i])j++;
if(j>=cnt)
{
if(j==cnt)ans=max(ans,w[i]-w[i-j]);
else ans=w[i]-w[i-j];
cnt=j;
}
}
}
int main()
{
scanf("%d %d",&n,&m);
scanf("%s",&B[1]);
scanf("%s",&A[1]);
for(int i=1;i<=m;i++)scanf("%d",&w[i]),w[i]+=w[i-1];
kmp();
printf("%d %d",cnt,ans);
}
E :
解:
这一题可以用图论知识来做。
如果
∣
S
i
−
S
j
∣
>
k
|S_i-S_j|>k
∣Si−Sj∣>k,那么在
i
,
j
i,j
i,j之间连一条双向边。
那么最后的答案就是在这个图中,经过所有节点一次的路径有多少条。
考虑一下暴力的
d
f
s
dfs
dfs
可能出现极端情况,图是一个无向完全图。
路径条数最大为
16
!
16!
16!条。显然会
T
T
T
于是考虑优化一下,用记忆化搜索。
设
f
[
i
]
[
s
]
f[i][s]
f[i][s]表示在
i
i
i号结点把集合
S
S
S中的结点走完的路径条数。
显然可以得到转移方程:
f
[
i
]
[
s
]
=
∑
k
∈
S
f
[
k
]
[
S
−
{
k
}
]
f[i][s]=\sum_{k\in S}f[k][S-\{k\}]
f[i][s]=k∈S∑f[k][S−{k}]
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lowbit(x) (x&-x)
bool g[20][20];
int s[20];
int n,k;
int ans;
ll f[17][1<<16];
int logg[1<<16];
ll dfs(int x,int s)//s中1代表未去过
{
if(f[x][s])return f[x][s];
for(int s1=s,k=lowbit(s1),i=logg[k]+1,s0=s^k;s1;s1^=k,k=lowbit(s1),i=logg[k]+1,s0=s^k)
if(g[x][i])f[x][s]+=dfs(i,s0);
return f[x][s];
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>s[i],g[0][i]=true,logg[1<<i]=i,f[i][0]=1;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(abs(s[i]-s[j])>k)g[i][j]=g[j][i]=true;
cout<<dfs(0,(1<<n)-1);
return 0;
}
注:注意本题数据范围。。。。。。。。。。
F:
解:
设有三个顾客
x
,
x
1
,
x
2
x,x_1,x_2
x,x1,x2,送客顺序是
x
→
x
1
→
x
2
x\rightarrow x_1\rightarrow x_2
x→x1→x2
情况一:
如果
x
1
x_1
x1位于
x
x
x和
x
2
x_2
x2之间,那么不送
x
1
x_1
x1的路程和送
x
1
x_1
x1的路程是一样。或者说:从
x
x
x去送
x
2
x_2
x2的时候顺便把
x
1
x_1
x1送了。
情况二:
如果
x
x
x送完
x
1
x_1
x1后要转向,那么不送
x
1
x_1
x1的路程比送
x
1
x_1
x1的路程少
d
i
s
x
→
x
1
×
2
dis_{x\rightarrow x_1}\times 2
disx→x1×2
那么对于最后一顾客,可以在添加一个位于原点的客户。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int a[maxn];
int n,k;
int sum=0;
int w[maxn];
int ans;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{scanf("%d",&a[i]);}
a[++n]=0;
for(int i=1;i<=n;i++)ans+=abs(a[i]-a[i-1]);
for(int i=2;i<=n;i++)
{
if((a[i]-a[i-1])*(a[i-1]-a[i-2])<0)w[i-1]=2*min(abs(a[i]-a[i-1]),abs(a[i-1]-a[i-2]));
}
for(int i=1;i<=n-1;i++)
printf("%d\n",ans-w[i]);
return 0;
}