第一次打div1,比较自闭。。
A.
因为
g
c
d
(
x
,
y
)
=
g
c
d
(
x
,
y
−
x
)
gcd(x,y)=gcd(x,y-x)
gcd(x,y)=gcd(x,y−x)。
那么
g
c
d
(
a
1
+
x
,
a
2
+
x
,
a
3
+
x
.
.
.
.
)
=
g
c
d
(
a
1
+
x
,
a
2
−
a
1
,
a
3
−
a
1
,
.
.
.
.
)
gcd(a_1+x,a_2+x,a_3+x....)=gcd(a_1+x,a_2-a_1,a_3-a_1,....)
gcd(a1+x,a2+x,a3+x....)=gcd(a1+x,a2−a1,a3−a1,....)
所以只需要给
a
a
a排序,并维护所有比
a
1
a_1
a1大的数
a
i
a_i
ai的
a
i
−
a
1
a_i-a_1
ai−a1的
g
c
d
gcd
gcd即可。注意可能所有数相同的情况。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#define LL long long
const int maxn=2e5+7;
using namespace std;
int n,m;
LL a[maxn],b[maxn];
LL p;
LL gcd(LL x,LL y)
{
LL r=x%y;
while (r)
{
x=y;
y=r;
r=x%y;
}
return y;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
for (int i=1;i<=m;i++) scanf("%lld",&b[i]);
sort(a+1,a+n+1);
for (int i=1;i<=n;i++)
{
if (a[i]!=a[1])
{
if (!p) p=a[i]-a[1];
else p=gcd(p,a[i]-a[1]);
}
}
for (int i=1;i<=m;i++)
{
if (!p) printf("%lld ",a[1]+b[i]);
else printf("%lld ",gcd(a[1]+b[i],p));
}
}
B.
可以理解为所选杯子的容积与转移到这些杯子的水量的最小值。
我们可以设
f
[
i
]
[
j
]
[
k
]
f[i][j][k]
f[i][j][k]表示前
i
i
i个杯子,选了
j
j
j个,容积为
k
k
k可以转移到的最大水量。
那么
f
[
i
]
[
j
]
[
k
]
=
m
a
x
(
f
[
i
−
1
]
[
j
]
[
k
]
+
b
[
i
]
/
2
,
f
[
i
−
1
]
[
j
−
1
]
[
k
−
a
[
i
]
]
+
b
[
i
]
)
f[i][j][k]=max(f[i-1][j][k]+b[i]/2,f[i-1][j-1][k-a[i]]+b[i])
f[i][j][k]=max(f[i−1][j][k]+b[i]/2,f[i−1][j−1][k−a[i]]+b[i])
把
i
i
i这一维滚动掉。
这题是很经典的设一维最优另一维的dp。
复杂度是
O
(
n
4
)
O(n^4)
O(n4),但不会跑满。
代码:
#include <iostream>
#include <cstdio>
const int maxn=107;
using namespace std;
int n;
int a[maxn],b[maxn],sum[maxn];
int f[2][maxn][maxn*maxn];
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d%d",&a[i],&b[i]);
sum[i]=sum[i-1]+a[i];
}
int p=0;
for (int i=1;i<=n;i++)
{
p=1-p;
for (int j=0;j<=i;j++)
{
for (int k=0;k<=sum[i];k++)
{
f[p][j][k]=-0x3f3f3f3f;
if (k<=sum[i-1]) f[p][j][k]=max(f[p][j][k],f[1-p][j][k]+b[i]);
if ((j>0) && (k>=a[i])) f[p][j][k]=max(f[p][j][k],f[1-p][j-1][k-a[i]]+b[i]*2);
}
}
}
for (int j=1;j<=n;j++)
{
int ans=0;
for (int k=0;k<=sum[n];k++) ans=max(ans,min(2*k,f[p][j][k]));
printf("%.5lf ",(double)ans/2);
}
}
C.
我们可以设一个三元组
(
i
,
j
,
k
)
(i,j,k)
(i,j,k)表示
a
[
i
]
[
j
]
=
k
a[i][j]=k
a[i][j]=k;
那么前面
4
4
4个操作相当于把
i
i
i,
j
j
j加一或者减一。
而求逆操作
I
I
I相当于交换
j
j
j与
k
k
k; 求逆操作
C
C
C相当于交换
i
i
i与
k
k
k;
所以我们只需要维护开始的三维最后在哪一位以及他们增加了多少即可。
因为每一位都是
[
1
,
n
]
[1,n]
[1,n],只需在求得模
n
n
n意义下的三元组,然后还原成数组即可。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
const int maxn=1e3+7;
const int maxs=1e5+7;
using namespace std;
int T,n,m,cnt;
int a[maxn*maxn][4],b[maxn*maxn][4],c[maxn][maxn];
int p[maxn],q[maxn];
char s[maxs];
int main()
{
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);
cnt=0;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
a[++cnt][1]=i;
a[cnt][2]=j;
scanf("%d",&a[cnt][3]);
}
}
for (int i=1;i<=3;i++) p[i]=0;
scanf("%s",s+1);
q[1]=1,q[2]=2,q[3]=3;
for (int i=1;i<=m;i++)
{
if (s[i]=='R') p[2]++;
if (s[i]=='L') p[2]--;
if (s[i]=='D') p[1]++;
if (s[i]=='U') p[1]--;
if (s[i]=='I') swap(q[2],q[3]),swap(p[2],p[3]);
if (s[i]=='C') swap(q[1],q[3]),swap(p[1],p[3]);
}
for (int i=1;i<=cnt;i++)
{
for (int j=1;j<=3;j++)
{
b[i][j]=((a[i][q[j]]+p[j])%n+n)%n;
if (b[i][j]==0) b[i][j]=n;
}
}
for (int i=1;i<=cnt;i++) c[b[i][1]][b[i][2]]=b[i][3];
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++) printf("%d ",c[i][j]);
printf("\n");
}
printf("\n");
}
}
D.
我们把
0
0
0看做
−
1
-1
−1,
1
1
1看做
1
1
1,令
s
i
s_i
si为前缀和,然后连一条
(
s
i
−
1
,
s
i
)
(s_{i-1},s_i)
(si−1,si)的边。
一个序列可以看做一个一条从
s
0
s_0
s0到
s
l
e
n
s_{len}
slen的欧拉路径。
我们可以发现每次操作相当于对欧拉路径上的一个环,将所有边反向,并将顺序颠倒。
可以知道,通过操作,每一条欧拉路径都是可以构造出来的,所以答案就是字典序最小的欧拉路径。
求字典序最小的欧拉路径:假设对于每一个节点 x x x,我们枚举按字典序从小到大递归他的相邻节点,同时删掉连向相邻节点的边。最后把 x x x加入序列 a a a。倒序输出 a a a就是字典序最小的欧拉路径。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
const int maxn=5e5+7;
using namespace std;
int T,n,cnt;
int a[maxn],b[maxn],ans[maxn];
char s[maxn];
vector <int> g[maxn];
void dfs(int x)
{
while (b[x])
{
int p=g[x][b[x]-1];
b[x]--;
dfs(p);
}
ans[++cnt]=x;
}
bool cmp(int x,int y)
{
return x>y;
}
int main()
{
scanf("%d",&T);
while (T--)
{
scanf("%s",s+1);
n=strlen(s+1);
int p=0,q=0;
a[0]=0;
for (int i=1;i<=n;i++)
{
if (s[i]=='0') a[i]=a[i-1]-1;
else a[i]=a[i-1]+1;
p=min(p,a[i]);
q=max(q,a[i]);
}
for (int i=0;i<=n;i++) a[i]-=p;
q-=p;
for (int i=0;i<=q;i++) g[i].clear();
for (int i=1;i<=n;i++) g[a[i-1]].push_back(a[i]);
for (int i=0;i<=q;i++)
{
b[i]=g[i].size();
sort(g[i].begin(),g[i].end(),cmp);
}
cnt=0;
dfs(a[0]);
for (int i=cnt;i>1;i--)
{
if (ans[i]-ans[i-1]==1) printf("0");
else printf("1");
}
printf("\n");
}
}