A
/* Author : Rshs */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define LDB long double
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const LDB pai = acos(-1.0L);
const LDB eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
char a[MXN],b[MXN];
int dp[1005][1005];
int main(){
cin>>(a+1)>>(b+1);
int la=strlen(a+1),lb=strlen(b+1);
for(int i=1;i<=la;i++) dp[i][0]=i;
for(int i=1;i<=lb;i++) dp[0][i]=i;
for(int i=1;i<=la;i++){
for(int j=1;j<=lb;j++){
if(a[i]==b[j]){
dp[i][j]=dp[i-1][j-1];
}
else {
dp[i][j]=min(dp[i-1][j],min(dp[i][j-1],dp[i-1][j-1]))+1;
}
}
}
cout<<dp[la][lb];
return 0;
}
B
dp转移的时候记录一下前驱就可以输出路径了。
/* Author : Rshs */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define LDB long double
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const LDB pai = acos(-1.0L);
const LDB eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
char a[MXN],b[MXN];
int dp[1005][1005];
PII pr[1005][1005];
int main(){
cin>>(a+1)>>(b+1);
int la=strlen(a+1),lb=strlen(b+1);
for(int i=1;i<=la;i++){
for(int j=1;j<=lb;j++){
if(a[i]==b[j]){
dp[i][j]=dp[i-1][j-1]+1;
pr[i][j]=MP(i-1,j-1);
}
else {
if(dp[i-1][j]>dp[i][j-1]) dp[i][j]=dp[i-1][j],pr[i][j]=MP(i-1,j);
else dp[i][j]=dp[i][j-1],pr[i][j]=MP(i,j-1);
}
}
}
int ans=0;
PII u;
for(int i=1;i<=la;i++){
for(int j=1;j<=lb;j++){
if(dp[i][j]>ans)ans=dp[i][j],u=MP(i,j);
}
}
vector<char>v;
while(ans){
if(a[u.FI]==b[u.SE]){
v.push_back(a[u.FI]);
ans--;
}
u=pr[u.FI][u.SE];
}
reverse(v.begin(),v.end());
for(auto i:v) cout<<i;
return 0;
}
C
自然而然想到要做成环,让S在末尾加上S的前20个。
有两个注意点:
1.注意S的长度小于10的时候,再按照上述方法操作,输入的匹配串可能会多次利用S的字母,这个时候直接暴力枚举S做成的len(S)种环。
2.注意是substring,注意转移方程和初始化。
/* Author : Rshs */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define LDB long double
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const LDB pai = acos(-1.0L);
const LDB eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
char s[MXN];
char tt[MXN];
int dp[MXN][20];
int main(){
while(scanf("%s",s+1)!=EOF){
int n=strlen(s+1);
if(n<=20){
int q;cin>>q;
int ans=INT_MAX;string u,t;
while(q--){
cin>>(t);
int m=t.length();
for(int _=0;_<n;_++){
for(int j=0;j<n;j++){
tt[(j+_)%n]=s[j+1];
}
for(int i=1;i<=n;i++) dp[i][0]=0;
for(int i=1;i<=m;i++) dp[0][i]=i;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(tt[i-1]==t[j-1]){
dp[i][j]=dp[i-1][j-1];
}
else {
dp[i][j]=dp[i-1][j]+1;
dp[i][j]=min(dp[i][j],dp[i][j-1]+1);
dp[i][j]=min(dp[i][j],dp[i-1][j-1]+1);
}
if(j==m){
if(dp[i][m]<ans) ans=dp[i][m],u=t;
if(dp[i][m]==ans&&t<u) u=t;
}
}
}
}
}
cout<<u<< ' '<<ans<<'\n';
continue;
}
int add=min(20,n);
for(int i=n+1;i<=n+add;i++){
s[i]=s[i-n];
}
n=n+add;
int q;cin>>q;
int ans=INT_MAX;string u,t;
while(q--){
cin>>(t);
int m=t.length();
for(int i=1;i<=n;i++) dp[i][0]=0;
for(int i=1;i<=m;i++) dp[0][i]=i;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(s[i]==t[j-1]){
dp[i][j]=dp[i-1][j-1];
}
else {
dp[i][j]=dp[i-1][j]+1;
dp[i][j]=min(dp[i][j],dp[i][j-1]+1);
dp[i][j]=min(dp[i][j],dp[i-1][j-1]+1);
}
if(j==m){
if(dp[i][m]<ans) ans=dp[i][m],u=t;
if(dp[i][m]==ans&&t<u) u=t;
}
}
}
}
cout<<u<< ' '<<ans<<'\n';
}
return 0;
}
D
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]:a的前i位和b的前j位可以组成的种类数。
容斥种类数。
/* Author : Rshs */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define LDB long double
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const LDB pai = acos(-1.0L);
const LDB eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
int a[MXN],b[MXN];
LL dp[1005][1005];
int main(){
int n,m;
while(cin>>n>>m){
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=m;i++)scanf("%d",&b[i]);
dp[0][0]=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i]==b[j]) dp[i][j]=(1+dp[i-1][j-1]+dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1])%mod;
else dp[i][j]=(dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1])%mod;
}
}
cout<<(dp[n][m]%mod+mod)%mod<<'\n';
}
return 0;
}
E
当n=1是,我是0,wa了。
/* Author : Rshs */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define LDB long double
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const LDB pai = acos(-1.0L);
const LDB eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
int main(){
int n;cin>>n;
if(n>36) cout<<-1;
else {
while(n>=2){
n-=2;
cout<<8;
}
if(n==1){
cout<<6;
}
}
return 0;
}
F
取最大值的最小值,无需分类讨论。
/* Author : Rshs */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define LDB long double
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const LDB pai = acos(-1.0L);
const LDB eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
int a[MXN],b[MXN];
int main(){
int n,m;cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int j=1;j<=m;j++) cin>>b[j];
LL mi=LLONG_MAX;
for(int i=1;i<=n;i++){
LL mx=LLONG_MIN;
for(int j=1;j<=n;j++){
if(i==j)continue;
for(int k=1;k<=m;k++){
mx=max(mx,(LL)a[j]*(LL)b[k]);
}
}
mi=min(mx,mi);
}
cout<<mi;
return 0;
}
G
没怎么动脑子,暴力考虑反转不反转。
用区间dp,O(1)转移代价。
/* Author : Rshs */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define LDB long double
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const LDB pai = acos(-1.0L);
const LDB eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
int a[MXN],p2[MXN],p1[MXN];
int dp[2005][2005],c[2005][2005];
int main(){
int n;cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n+1;i++){
p2[i]=p2[i-1]+(a[i]==2);
p1[i]=p1[i-1]+(a[i]==1);
}
for(int i=1;i<=n;i++) c[i][i]=1;
for(int i=2;i<=n;i++){
for(int j=1;j<=n;j++){
if(j+i-1>n) break;
int r=j+i-1,l=j;
if(a[r]==2) c[l][r]=c[l][r-1]+1;
else c[l][r]=c[l][r-1];
c[l][r]=max(c[l][r],p2[r]-p2[l-1]);
c[l][r]=max(c[l][r],p1[r]-p1[l-1]);
}
}
for(int i=1;i<=n;i++) dp[i][i]=1;
for(int i=2;i<=n;i++){
for(int j=1;j<=n;j++){
if(j+i-1>n) break;
int r=j+i-1,l=j;
if(a[r]==1) dp[l][r]=dp[l][r-1]+1;
else dp[l][r]=dp[l][r-1];
dp[l][r]=max(dp[l][r],p2[r]-p2[l-1]);
dp[l][r]=max(dp[l][r],p1[r]-p1[l-1]);
}
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
ans=max(ans,p1[i-1]+p2[n]-p2[j]+max(dp[i][j],c[i][j]));
}
}
cout<<ans<<'\n';
return 0;
}
H
f
0
=
p
+
k
∗
g
0
f_0=p+k*g_0
f0=p+k∗g0
f
1
=
g
0
+
k
∗
g
1
f_1=g_0+k*g_1
f1=g0+k∗g1
f
2
=
g
1
+
k
∗
g
2
f_2=g_1+k*g_2
f2=g1+k∗g2
…
f
x
=
g
x
−
1
+
k
∗
g
x
f_x=g_{x-1}+k*g_x
fx=gx−1+k∗gx
然后方程代换消去g可以得到:
p
=
f
0
−
k
∗
f
1
+
k
2
∗
f
2
.
.
.
+
k
x
∗
f
k
p=f_0-k*f_1+k^2*f_2...+k^x*f_k
p=f0−k∗f1+k2∗f2...+kx∗fk
然后这个东西就是负进制(-k进制)。
问题转化为求p的-k进制。
具体做法看代码。
/* Author : Rshs */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define LDB long double
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const LDB pai = acos(-1.0L);
const LDB eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
int main(){
LL p,k;cin>>p>>k;
vector<LL>v;
while(p){//和正数进制差不多
LL s=p/(-k);
LL y=p%(-k);
if(y<0) y+=k,s++; //不能出现负数
if(y>k) {puts("-1");return 0;}
v.push_back(y);
p=s;
}
cout<<SZ(v)<<'\n';
for(auto i:v)cout<<i<< ' ' ;
return 0;
}
I
我写撒点,写的稀碎。。。但是精度有问题好像,而且t了。
正解用平面上的欧拉公式。先记个结论。
平面上的欧拉公式:V - E + R = C + 1,其中 V(vertex) 表示交点数目,E(edge) 表示边数,R(region) 表示区域数,C(connection) 用来分割的线所构成的连通块个数。