AtCoder Beginner Contest 287(C,D,E,F)
AtCoder Beginner Contest 287(C,D,E,F)
C (图)
题目大意为
这个就直接判断每个点的度,我们发现只存在两个点的度是
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
#include <numeric>
using namespace std;
#define int long long
#define LL long long
#define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define inf 1e18
#define INF 1e18
#define mem(a,b) memset((a),(b),sizeof(a))
const int maxn=2e5+10;
const int mod=998244353;
vector<int>f,d;
int n,m;
int find(int x)
{
if(f[x]==x) return x;
return f[x]=find(f[x]);
}
void merge(int x,int y)
{
int tx=find(x),ty=find(y);
if(tx==ty) return ;
f[ty]=tx;
return ;
}
signed main ()
{
cin>>n>>m;
f.resize(n+1);
d.resize(n+1);
iota(f.begin(),f.end(),0);
for (int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
d[u]++;
d[v]++;
merge(u,v);
}
if(m!=n-1)
{
cout<<"No\n";
system ("pause");
return 0;
}
int cnt2=0,cnt1=0;
cnt1=count(d.begin(),d.end(),1);
cnt2=count(d.begin(),d.end(),2);
int cnt=0;
for (int i=1;i<=n;i++)
{
if(i==f[i])
{
cnt++;
}
}
if(cnt1==2&&cnt2==n-2&&cnt==1)
{
cout<<"Yes\n";
}
else
{
cout<<"No\n";
}
system ("pause");
return 0;
}
这次竟然
D(思维)
题目大意就是给出一个
对于
对于匹配问题,两个字符串如果是已定字符,如果是一样就可能是可以匹配的,因为我们还会存在一种代表未知字符的
记录一下我的写法
那么对于两个一样的,我发现只要前面一段存在不匹配的情况后面,后面
所以,我们提前求出最长的可匹配前缀长度和最长的可匹配后缀的长度
然后这两个长度都有着自己可以满足的
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
using namespace std;
#define int long long
#define LL long long
#define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define inf 1e18
#define INF 1e18
#define mem(a,b) memset((a),(b),sizeof(a))
const int maxn=2e5+10;
const int mod=998244353;
string s,t;
int n,m;
signed main ()
{
cin>>s>>t;
n=s.size(),m=t.size();
s=" "+s;
t=" "+t;
int pre=0,suf=0;
for (int i=1;i<=m;i++)
{
if(s[i]==t[i])
{
pre++;
}
else if(s[i]=='?'||t[i]=='?')
{
pre++;
}
else break;
}
for (int i=n,j=m;i>=1&&j>=1;i--,j--)
{
if(s[i]==t[j])
{
suf++;
}
else if(s[i]=='?'||t[j]=='?')
{
suf++;
}
else
{
break;
}
}
int l=0,r=pre;
int ll=m-suf,rr=m;
int L=max(l,ll),R=min(r,rr);
for (int i=0;i<=m;i++)
{
if(i>=L&&i<=R)
{
cout<<"Yes\n";
}
else
{
cout<<"No\n";
}
}
system ("pause");
return 0;
}
E(字典树/思维)
这个题的大意是有
每次都会问
即
这个题我写了两种不同的写法
第一种是字典树
这个应该很多人都看出来了,但是我对这个字典树还不是很熟练,就没有想到
我们就是把每一个字符都加到字典树里面去,然后去寻找
其他就没有什么好讲的了
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
#include <numeric>
using namespace std;
#define int long long
#define LL long long
#define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define inf 1e18
#define INF 1e18
#define mem(a,b) memset((a),(b),sizeof(a))
const int maxn=5e5+10;
const int mod=998244353;
string s[maxn];
struct Tire
{
int val,son[27];
}tr[maxn];
int n;
int idx;
int f(char ch)
{
int res=ch-'a';
return res;
}
void init()
{
for (int i=0;i<=idx;i++)
{
tr[i].val=0;
for (int j=0;j<26;j++)
{
tr[i].son[j]=0;
}
}
idx=0;
}
void insert(string s)
{
int rt=0;
for (int i=0;i<s.size();i++)
{
int now=f(s[i]);
if(!tr[rt].son[now])
{
tr[rt].son[now]=++idx;
}
rt=tr[rt].son[now];
tr[rt].val++;
}
return ;
}
int query(string s)
{
int rt=0;
for (int i=0;i<s.size();i++)
{
int now=f(s[i]);
rt=tr[rt].son[now];
if(tr[rt].val<=1)
{
return i;
}
}
return s.size();
}
signed main ()
{
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>s[i];
insert(s[i]);
}
for (int i=1;i<=n;i++)
{
int ans=query(s[i]);
cout<<ans<<"\n";
}
system ("pause");
return 0;
}
另外一种写法真的很妙
就是他先把字符串按照从到大小的顺序排序,然后我们可以知道两个相邻大小的字典序,他们才是可能最大的最长公共前缀长度(字典序相差越小,最长公共前缀长度越大)
所以我们这个还需要记录下字符串的位置
具体可看代码
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
#include <numeric>
using namespace std;
#define int long long
#define LL long long
#define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define inf 1e18
#define INF 1e18
#define mem(a,b) memset((a),(b),sizeof(a))
const int maxn=5e5+10;
const int mod=998244353;
int n;
struct node
{
int id;
string s;
}a[maxn];
int ans[maxn];
bool cmp(node x,node y)
{
return x.s<y.s;
}
int LCP(string s,string t)
{
int i=0,j=0;
int res=0;
while (i<s.size()&&j<t.size())
{
if(s[i]==t[j])
{
i++;
j++;
res++;
}
else break;
}
return res;
}
signed main ()
{
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>a[i].s;
a[i].id=i;
}
sort(a+1,a+1+n,cmp);
for (int i=1;i<n;i++)
{
int p=LCP(a[i].s,a[i+1].s);
int x=a[i].id;
int y=a[i+1].id;
ans[x]=max(ans[x],p);
ans[y]=max(ans[y],p);
}
for (int i=1;i<=n;i++)
{
cout<<ans[i]<<"\n";
}
system ("pause");
return 0;
}
F(树形dp)
给出一棵树,我们可以选择任意个点,问连通分量为
我树形
一开始是想把
上面是我们胡思乱想
下面才是正解
上面我自己想到的是拆分,而这个是合并
把以
如果这两个点都选择了,那么得到的连通分量为
然后我们每一次都会枚举不同的连连通分量个数,然后不断的更新
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
#include <numeric>
using namespace std;
#define int long long
#define LL long long
#define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define inf 1e18
#define INF 1e18
#define mem(a,b) memset((a),(b),sizeof(a))
const int maxn=5e3+10;
const int mod=998244353;
int n;
int siz[maxn];
vector<int>g[maxn],dp[maxn][2];
void add(int &x,int c)
{
x+=c;
if(x>=mod)
{
x-=mod;
}
return ;
}
void dfs(int u,int fa)
{
siz[u]=1;
dp[u][0].resize(2);
dp[u][0][0]=1;
dp[u][0][1]=0;
dp[u][1].resize(2);
dp[u][1][0]=0;
dp[u][1][1]=1;
for (auto v:g[u])
{
if(v==fa) continue;
dfs(v,u);
vector<int>tmp[2];
tmp[0].resize(siz[u]+siz[v]+1,0);
tmp[1].resize(siz[u]+siz[v]+1,0);
for (int i=0;i<=siz[u];i++)
{
for (int j=0;j<=siz[v];j++)
{
add(tmp[0][i+j],(dp[u][0][i]*dp[v][0][j])%mod);
add(tmp[0][i+j],(dp[u][0][i]*dp[v][1][j])%mod);
add(tmp[1][i+j],(dp[u][1][i]*dp[v][0][j])%mod);
if(i+j>=1)
{
add(tmp[1][i+j-1],(dp[u][1][i]*dp[v][1][j])%mod);
}
}
}
siz[u]+=siz[v];
dp[u][0]=tmp[0],dp[u][1]=tmp[1];
}
return ;
}
signed main ()
{
cin>>n;
for (int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
for (int i=1;i<=n;i++)
{
int ans=dp[1][0][i];
add(ans,dp[1][1][i]);
cout<<ans<<"\n";
}
system ("pause");
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)