noip模拟28
A. 遗忘之祭仪
应该是很简单的题.
快结束的时候想到了,所以就是没有在考场上\(A\)掉.
这里是比较清奇的思路.
首先将整个矩阵变成一个序列,然后我们考虑去匹配.
考虑一个问题:
如果我们在序列中匹配了,那么我们一定能在矩阵中匹配到吗..?
答案是否定的,自己举个例子就好了.
但是如果我们在矩阵最后再添上一列没有用的符号.
那么我们再次把\(ta\)变成序列匹配时,
我们就可以在矩阵中也成功匹配了.
首先我们将模式串的前面冗余的符号删掉,让\(ta\)的第一个符号为'x'.
然后我们将开头的位置挪到文本串中的每个尚未被匹配的第一个位置.
之后再去一个个匹配,类似于链表,当然也可以使用链表实现.
如果匹配失败了就输出\(No\)就可以了.
类似于线性筛.
注意不要输出\(YES/NO\),要输出\(Yes/No\).
A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
#define p() printf("Pass")
#define ll long long int
#define ull unsigned ll
#define re register ll
#define lf double
#define lb lower_bound
#define ub upper_bound
#define mp make_pair
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define Fill(x,y) memset(x,y,sizeof x);
#define Copy(x,y) memcpy(x,y,sizeof x);
inline ll read()
{
ll ss=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
return cit?ss:-ss;
}
inline void write(ll ss)
{
static int stas[35]; int topps=0;
if(ss<0) putchar('-'),ss=-ss;
do{stas[++topps]=ss%10,ss/=10;}while(ss);
while(topps) putchar(stas[topps--]+48); puts("");
}
} using namespace BSS;
const ll N=1e3+50,MN=2e6+50;
ll m,n,ts,c,d,lmt,cnt,ls,lt;
ll up1,up2,down1,down2;
ll t[MN],s[MN],dis[MN],pos[MN],vis[MN];
ll f[N][N],g[N][N],r[N][N];
ll pres,pret;
inline ll ksm(ll a,ll b,ll c)
{
a%=c; ll temp=1;
while(b)
{
if(b&1) temp=(temp*a)%c;
a=(a*a)%c; b>>=1;
}
return temp%c;
}
inline void Init()
{
char s2[N];
ll temp;
Fill(t,0); Fill(s,0);
n=read(),m=read(),c=read(),d=read();
Fill(f,0); Fill(t,0);
for(re i=1;i<=n;i++)
{
scanf("%s",s2+1);
for(re j=1;j<=m;j++)
{
f[i][j]= (s2[j]=='x') ;
}
}
up1=3e3,up2=3e3,down1=-1,down2=-1;
for(ll i=1;i<=c;i++)
{
scanf("%s",s2+1);
for(ll j=1;j<=d;j++)
{
r[i][j]= (s2[j]=='x');
if(r[i][j])
{
up1=min(up1,i),down1=max(down1,i);
up2=min(up2,j),down2=max(down2,j);
}
}
}
}
inline void Work()
{
Fill(vis,0); Fill(g,0); Fill(s,0);
Fill(dis,0); Fill(pos,0); Fill(t,0);
ls=0; lt=0; lmt=0;
if(up1-down1>n or up2-down2>m)
{
printf("No\n");
return ;
}
for(re i=1,ii=up1;ii<=down1;i++,ii++)
{
for(re j=1,jj=up2;jj<=down2;j++,jj++)
{
g[i][j]=r[ii][jj];
}
}
cnt=0;
for(re i=1;i<=n;i++)
{
for(re j=1;j<=m+1;j++)
{
if(g[i][j] or cnt) s[++cnt]=g[i][j];
if(s[cnt]) lmt=max(lmt,cnt);
if(g[i][j])
{
pos[++ls]=cnt;
}
}
}
for(re i=2;i<=ls;i++)
{
dis[i]=pos[i]-pos[i-1];
}
cnt=0;
for(re i=1;i<=n;i++)
{
for(re j=1;j<=m+1;j++)
{
t[++cnt]=f[i][j];
}
}
ll temp;
for(re i=1;i<=cnt;i++)
{
if(t[i] and vis[i]==0)
{
temp=i;
for(re j=1;j<=ls;j++)
{
temp+=dis[j];
if(!t[temp])
{
printf("No\n");
return ;
}
vis[temp]=1;
}
}
}
printf("Yes\n");
}
signed main()
{
// File(0.in,out);
ts=read();
while(ts--)
{
Init(); Work();
}
return 0;
}
B. 客星璀璨之夜
一个期望题目.
思路来自\(zero4338\).
考虑将每个段被经过的期望次数求出,然后再去乘以距离即可.
然后我们发现,如果我们把距离转化成次数.
那么宏观上看起来就很一样了..
大概就是:都是求次数,那么肯定不同点就减少了,或许递推是可行的.
于是我们就可以将思路集中到\(dp\)上:
又是一个分类讨论从而得到所有的方案数.
这里的详细讲解建议参考\(zero4338\)大佬.
其中有一个相似的情况:
注意到 \(j\) 是偶数时 ,\(f_{i,j}=f_{i,j+1}\) , 因为除了第 \(j+1\) 个反物质 , 其他反物质经过这段位移时肯定是两段一起被经过 , 而第 \(j+1\) 个反物质对两者的贡献又是相同的 .
所以可以选择在调用 \(f_{i,j+1}\) 的状态时,直接调用 \(f_{i,j}\) 就好了.
C. 割海成路之日
第一问:
发现如果\(t\)和\(s\)只需要经过\(1,2\)类型的边或者\(t\)在经过\(1,2\)之后,又经过了一条\(3\),之后只需要通过\(1\)便可以到到\(s\),那么答案即为可行,反之为不行
第二问:
发现对于所有的点,到达\(s\)的条件和\(t\)一样,所以统计点数就可以.
所以选择并查集维护每个点所在的\(1,2\)联通块和\(1\)联通块和每个联通块的大小即可,在合并并查集的时候用并查集就可以判断边的类型,然后更新点数即可,代码不是很难.
C_code
#include
using namespace std;
namespace BSS
{
#define ll int
#define ull unsigned ll
#define re register ll
#define lf double
#define lb lower_bound
#define ub upper_bound
#define mp make_pair
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define Fill(x,y) memset(x,y,sizeof x);
#define Copy(x,y) memcpy(x,y,sizeof x);
inline ll read()
{
ll ss=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
return cit?ss:-ss;
}
} using namespace BSS;
const ll N=3e5+21;
ll m,n,ts;
ll dep[N],head[N],f[N],ans[N];
struct I { ll u,v,w,nxt; } e[N<<1];
struct Graph {
ll fa[N]={0},siz[N];
ll find(ll x){ return x==fa[x] ? x : fa[x]=find(fa[x]) ; }
inline void Pre(){ for(re i=1;i<=n;i++) fa[i]=i,siz[i]=1; }
inline void merge(ll u,ll v){
siz[find(u)]+=siz[find(v)],fa[find(v)]=find(u);
}
} A,B;
inline void add(ll u,ll v,ll w){
e[++ts].u=u,e[ts].v=v,e[ts].w=w,e[ts].nxt=head[u],
head[u]=ts;
}
void dfs(ll u,ll depth){
dep[u]=depth;
for(re i=head[u];i;i=e[i].nxt){
if(dep[e[i].v]!=n+1) continue;
if(e[i].w<=1) A.merge(u,e[i].v);
if(e[i].w<=2) B.merge(u,e[i].v);
f[e[i].v]=u,dfs(e[i].v,depth+1);
ans[A.find(u)]+=B.siz[B.find(e[i].v)]*(e[i].w==3);
}
}
signed main(){
n=read(),m=read(); ll u,v,w,res;
for(re i=1;i<=n;i++) dep[i]=n+1;
for(re i=2;i<=n;i++)
u=read(),v=read(),w=read(),add(u,v,w),add(v,u,w);
A.Pre(),B.Pre(),dfs(1,1);
while(m--){
u=read(),v=read();
if(dep[u]>dep[v]) swap(u,v);
if(B.find(u)!=B.find(v)){
ans[A.find(f[B.find(u)])]+=B.siz[B.find(v)],
ans[A.find(u)]-=B.siz[B.find(v)],
B.merge(u,v);
}
else if(A.find(u)!=A.find(v)){
ans[A.find(u)]+=ans[A.find(v)],
A.merge(u,v);
}
u=read(),v=read();
if(B.find(u)==B.find(v)) res=1;
else if(A.find(f[B.find(v)])==A.find(u)) res=1;
else if(B.find(f[A.find(u)])==B.find(v)) res=1;
else res=0; printf("%d ",res);
res=B.siz[B.find(u)]+ans[A.find(u)];
res+=B.siz[B.find(f[A.find(u)])]*(B.find(f[A.find(u)])!=B.find(u));
printf("%d\n",res);
}
exit(0);
}
/*
4 2
2 1 3
3 2 3
4 1 3
4 1 1 2
3 2 3 1
*/

浙公网安备 33010602011771号