D.Gourmet choice
题意:给定你 n + m n+m n+m个数的大小关系,有等于,大于和小于,让你构造出原序列,使得最大值尽可能的小。
题解:考虑相等的数都是等价的,那么我们不妨通过并查集把所有的相等的数缩成一个联通块 ( t a r j a n (tarjan (tarjan也可以),然后由于大于关系,比一个数大的数必须至少多1,那么我们对于一个不等关系,每次将小的数连向大的数,那么就会构成一张 d a g dag dag(存在环一定不合法),直接 d f s dfs dfs或者拓扑排序求一个最短路就 o k ok ok
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk make_pair
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 4010;
const int maxm = 2e6+1e2;
char s[2010][2010];
int fa[maxn];
int point[maxn],nxt[maxm],to[maxm];
int deep[maxn];
int cnt,n,m;
int in[maxn];
queue<int> q;
void addedge(int x,int y)
{
nxt[++cnt]=point[x];
to[cnt]=y;
in[y]++;
point[x]=cnt;
}
int find(int x)
{
if (fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
int ans[maxn];
bool tpsort()
{
for (int i=1;i<=n+m;i++)
{
if (in[i]==0 && find(i)==i) q.push(i),ans[i]=1;
}
while (!q.empty())
{
int x = q.front();
q.pop();
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
in[p]--;
ans[p]=max(ans[p],ans[x]+1);
if (!in[p])
q.push(p);
}
}
int tot=0;
for (int i=1;i<=n+m;i++)
{
if (in[i]!=0) tot++;
}
return tot==0;
}
int main()
{
n=read(),m=read();
for (int i=1;i<=n+m;i++) fa[i]=i;
for (int i=1;i<=n;i++)
{
scanf("%s",s[i]+1);
}
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
if (s[i][j]=='=')
{
int f1 = find(i);
int f2 = find(j+n);
if (f1==f2) continue;
fa[f1]=f2;
}
}
for (int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
int f1 = find(i);
int f2 = find(j+n);
if (s[i][j]=='<')
addedge(f1,f2);
if (s[i][j]=='>')
addedge(f2,f1);
}
if(tpsort())
{
cout<<"Yes"<<endl;
for (int i=1;i<=n;i++) cout<<ans[find(i)]<<" ";
cout<<endl;
for (int i=1;i<=m;i++) cout<<ans[find(i+n)]<<" ";
cout<<endl;
}
else
{
cout<<"No"<<endl;
}
return 0;
}
1131E - String Multiplication
题意:懒得翻译了
题解:考虑到我们求的是最长的相同的字母的长度,所以每一种字母的贡献可以分开考虑,那么不妨枚举每个字母进行答案的更新。
考虑同一个字母应该怎么计算答案,可以发现,如果我们进行一次乘法,如果下一个串全是当前字母,那么就可以直接
n
o
w
+
=
(
n
o
w
+
1
)
∗
l
e
n
now+=(now+1)*len
now+=(now+1)∗len,
n
o
w
now
now表示当前字母目前最长的
a
n
s
ans
ans。表示我们可以直接用 第二个串包住所有
n
o
w
now
now的字符的新串来更新答案,类似
a
a
a
+
a
+
a
a
a
.
.
.
.
aaa+a+aaa....
aaa+a+aaa....
如果下一个串不全是当前字母,我们会发现,答案就是最长前缀+最长后缀+
(
n
o
w
=
=
1
)
(now==1)
(now==1),形如
a
b
a
a
+
′
a
′
+
a
b
a
a
abaa+'a'+abaa
abaa+′a′+abaa的形式
然后就可以做辣
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk make_pair
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 1e5+1e2;
string s[maxn];
int n,ans;
bool check(int x,char c)
{
int len = s[x].length();
for (int i=0;i<len;i++)
if (s[x][i]!=c) return false;
return true;
}
int main()
{
n=read();
for (int i=1;i<=n;i++) cin>>s[i];
for (char i='a';i<='z';i++)//每一个字母单独考虑,维护前缀和后缀等信息
{
int pre=0,suf=0,now=0;
for (int j=1;j<=n;j++)
{
int len = s[j].length();
if(check(j,i))//如果全是一样的,那么原本的ans,就可以被ans+1个此串包起来,前缀和后缀同理
{
pre+=(pre+1)*len;
suf+=(suf+1)*len;
now+=(now+1)*len;
}
else
{
pre=0;suf=0;
for (int k=0;k<len && s[j][k]==i;k++) pre++;
for (int k=len-1;k>=0 && s[j][k]==i;k--) suf++;
if (now!=0) //形如 ...... + ans[i]+ ......的形式 ans[i]和点都是一样的字母
now=pre+suf+1;
else
now = max(pre,suf); //如 ...... + ans[i]+ ......的形式 ans[i]和点 不 是 一样的字母 !
int ymh = 0;
for (int k=0;k<len;k++) //串本身的ans
{
if (s[j][k]!=i)
now = max(now,ymh),ymh=0;
else ymh++;
}
now=max(now,ymh);
}
//cout<<i<<" "<<j<<" "<<now<<endl;
}
ans=max(ans,now);
}
cout<<ans;
return 0;
}
1131F - Asya And Kittens
题意:qwq
题解:
题意可以直接转化成给你
n
n
n个点,每次连接两个点所在的联通块,使得最后的联通块是一条链
直接启发式合并,合并的时候,大的联通块挂在小的联通块的最深的点的底下,这样合并是正确的。qwq画图可知
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<cstdlib>
#define pb push_back
#define mk make_pair
#define ll long long
#define lson ch[x][0]
#define rson ch[x][1]
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 3e5+1e2;
const int maxm = 2*maxn;
int point[maxn],nxt[maxm],to[maxm];
int cnt,n,m;
int x[maxm],y[maxm];
int fa[maxn];
int in[maxn];
int size[maxn];
int deep[maxn];
int mx,mxpos;
void addedge(int x,int y)
{
nxt[++cnt]=point[x];
to[cnt]=y;
point[x]=cnt;
}
int find(int x)
{
if (fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
void dfs(int x,int fa)
{
deep[x]=deep[fa]+1;
if(mx<deep[x]) mx=deep[x],mxpos=x;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (p==fa) continue;
dfs(p,x);
}
}
void solve(int x,int fa)
{
cout<<x<<" ";
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (p==fa) continue;
solve(p,x);
}
}
int main()
{
n=read();
for (int i=1;i<n;i++) x[i]=read(),y[i]=read();
for (int i=1;i<=n;i++) fa[i]=i,size[i]=1;
for (int i=1;i<n;i++)
{
int f1 = find(x[i]);
int f2 = find(y[i]);
if (size[f1]<size[f2]) swap(f1,f2);
mx=0;
dfs(f2,0);
addedge(f1,mxpos);
addedge(mxpos,f1);
size[f2]+=size[f1];
fa[f1]=mxpos;
}
int ff = find(1);
solve(ff,0);
return 0;
}
``