A题
题解:
题意告诉我们一棵bfs序树让我们求每个叶子节点与编号小于其的叶子节点的路径的最小值。
可以想到的是在每个节点中记录一个f数组表示其离最近的叶子节点的距离。
那这样我们只要保证对于每一次枚举叶子节点后更新后的树上的f数组是正确的,在下一次枚举到
时,向上dfs的过程中发现有一个节点被更新过,则该叶子节点的答案就是f[x]+f[pre]+1
。
但是要注意的是,更新完后我们还要进行一次回溯,因为可能回溯过程中的节点f值是深度较小的叶子节点。因此还要进行一步f[x]=min(f[x],f[y]+1)
的操作(wa了6发)
代码:
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 0x3f3f3f3f
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=4e6+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//逆元
int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
int indeg[N],f[N];
bool mark;
int ans;
void dfs(int x,int pre){
if(f[x]!=-1){
mark=true;
ans=f[x]+f[pre]+1;
return;
}
else f[x]=f[pre]+1;
for(int i=head[x];i;i=NEXT[i]){
int y=ver[i];
dfs(y,x);
f[x]=min(f[x],f[y]+1);
}
}
int main(){
int n;
int u;
scanf("%d",&n);
for(int i=2;i<=n;i++){
scanf("%d",&u);
link(i,u);
indeg[u]++;
}
memset(f,-1,sizeof(f));
for(int i=1;i<=n;i++){
if(indeg[i]) continue;
mark=false;
dfs(i,0);
if(mark){
printf("%d %d\n",i,ans);
}
else {
printf("%d -1\n",i);
}
}
return 0;
}
D题:
题解:
题目大概意思是在
2
n
2n
2n个字中填左空右三个字 其中左右不能连续,空只能连续
2
2
2个一起存在,且左右的个数一样。由于
n
n
n很小只有
20
20
20,于是想到了一个
5
5
5维的
d
p
dp
dp
dp[i][j][k][p][q]
其中
i
i
i表示第
i
i
i位,
j
j
j表示前
i
i
i位有几个左,
k
k
k表示前
i
i
i位有几个右,
p
p
p表示当前位置有连续几个空,
q
q
q表示当前位置插入的是左·右·空(1·2·3),然后就可以按题意模拟转移方程了,详见代码
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
#include <set>
#include <sstream>
#include <vector>
#include <stdlib.h>
#include <algorithm>
using namespace std;
#define dbg(x) cout<<#x<<" = "<< (x)<< endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl
#define MOD 998244353
long long dp[55][50][50][5][5];
int main()
{
int n;
scanf("%d",&n);
dp[1][1][0][0][1] = 1;
dp[1][0][1][0][2] = 1;
dp[1][0][0][1][3] = 1;
for(int i = 2;i<=2*n;i++)
{
for(int j = 0;j<=i;j++)
{
for(int k = 0;k<=i;k++)
{
if(i==2*n&&j!=k) continue;
if(k+j>i) continue;
if(j>=1)
dp[i][j][k][0][1] += dp[i-1][j-1][k][0][1];
dp[i][j][k][0][1] += dp[i-1][j-1][k][2][3];
dp[i][j][k][0][1]%=MOD;
//dbg3(i,j,k);
//dbg(dp[i][j][k][0][1]);
if(k>=1)
dp[i][j][k][0][2] += dp[i-1][j][k-1][0][2] ;
dp[i][j][k][0][2] += dp[i-1][j][k-1][2][3];
dp[i][j][k][0][2]%=MOD;
//dbg(dp[i][j][k][0][2]);
dp[i][j][k][1][3] += dp[i-1][j][k][0][1]+dp[i-1][j][k][0][2];
dp[i][j][k][1][3] %= MOD;
//dbg(dp[i][j][k][1][3]);
dp[i][j][k][2][3] += dp[i-1][j][k][1][3];
dp[i][j][k][2][3] %= MOD;
//dbg(dp[i][j][k][2][3]);
}
}
}
long long ans = 0;
for(int i = 0;i<n;++i)
{
//dbg(i);
ans+=dp[2*n][i][i][0][1] + dp[2*n][i][i][0][2] + dp[2*n][i][i][2][3];
//dbg3(dp[2*n][i][i][0][1] , dp[2*n][i][i][0][2] , dp[2*n][i][i][2][3]);
ans%=MOD;
}
printf("%lld\n",ans);
return 0;
}
G题:
题解:
可以将原题中的i*fi
转化成将矩阵分成小块即
1
1
1的个数,于是问题就又变成在
n
∗
m
n*m
n∗m的矩阵中值为1的子矩阵个数总和,通俗讲就是假如
(
1
,
2
)
(
3
,
3
)
(1,2)(3,3)
(1,2)(3,3)中值是1,那
a
n
s
ans
ans就是包括
(
1
,
2
)
(1,2)
(1,2)的矩阵个数
+
+
+包括
(
3
,
3
)
(3,3)
(3,3)的矩阵个数。
代码:
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 0x3f3f3f3f
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=998244353;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//逆元
//int head[N],NEXT[M],ver[M],tot;void link(int u,int v,ll w){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;wei[tot]=w;}
char str[2200][2200];
int main(){
ll n,m;
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",str[i]+1);
}
ll ans=0;
for(ll i=1;i<=n;i++){
for(ll j=1;j<=m;j++){
if(str[i][j]!='1') continue;
ans+=(((((i*(n-i+1LL))%mod)*j)%mod)*(m-j+1LL))%mod;
ans%=mod;
}
}
printf("%lld\n",ans);
return 0;
}
( 未 完 待 续 ) (未完待续) (未完待续)