Codeforces Round #566 (Div. 2)
前言
md终于紫了,纪念一下
A
题意
用若干\(\begin{matrix}\Box\blacksquare\\\blacksquare\blacksquare\end{matrix}\)以及旋转\(90^\circ,180^\circ,270^\circ\)的版本填充\(3*n\)的方格,问方案
题解
自己看代码,懒得写了
n=rd();
if(n&1) puts("0");
else
{
n>>=1;
cout<<(1ll<<n);
}
B
题意
问一个字符矩阵是否存在一个加号,且其他格子为空
题解
模拟
注意细节即可
#include<bits/stdc++.h>
#define db long double
#define il inline
#define re register
using namespace std;
const int N=500+10,mod=998244353;
int rd()
{
int x=0,w=1;char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int n,m,tt;
char cc[N][N];
int main()
{
n=rd(),m=rd();
for(int i=1;i<=n;++i) scanf("%s",cc[i]+1);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
tt+=cc[i][j]=='*';
for(int i=2;i<n;++i)
for(int j=2;j<m;++j)
if(cc[i][j]=='*'&&cc[i-1][j]=='*'&&cc[i+1][j]=='*'&&cc[i][j-1]=='*'&&cc[i][j+1]=='*')
{
int cn=1;
for(int k=i-1;cc[k][j]=='*';--k) ++cn;
for(int k=i+1;cc[k][j]=='*';++k) ++cn;
for(int k=j-1;cc[i][k]=='*';--k) ++cn;
for(int k=j+1;cc[i][k]=='*';++k) ++cn;
puts(cn==tt?"YES":"NO");
return 0;
}
puts("NO");
return 0;
}
C
题意
定义鸡你太美为四个单词组成的,每行两个单词的东西,其中第一行第一个单词和第二行第一个单词元音字母(\(a,e,o,i,u\))个数要相同,第一行第二个单词和第二行第二个单词元音字母个数要相同,每行最后一个元音字母要相同.现在给出一些单词,每个只能用一个,问最多拼出多少个鸡你太美并输出方案
题解
在单词中尽可能凑出元音字母个数相同最后一个元音相同的单词对,再从剩下的凑出元音字母个数相同的单词对,然后前者可以作为每行第一个以及第二个单词对,后者只能放第一个,所以记个数分别为\(n,m\),答案为\(min(\lfloor\frac{n+m}{2}\rfloor,n)\),方案就尽可能用后者放第一个构造即可
#include<bits/stdc++.h>
#define db long double
#define il inline
#define re register
using namespace std;
const int N=1e5+10,M=N*10;
int rd()
{
int x=0,w=1;char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int n,m;
char cc[M];
string ss[N];
int a[M][5];
vector<int> ls[M][5];
struct node{int x,y;};
int res[M],to[128];
vector<node> c1,c2;
int main()
{
memset(to,-1,sizeof(to));
to['a']=0;
to['e']=1;
to['i']=2;
to['o']=3;
to['u']=4;
n=rd();
for(int i=1;i<=n;++i)
{
scanf("%s",cc);
int len=strlen(cc);
int cn=0,la=0;
for(int j=0;j<len;++j)
{
ss[i].push_back(cc[j]);
if(to[(int)cc[j]]>=0)
++cn,la=to[(int)cc[j]];
}
m=max(m,cn);
if(cn) ++a[cn][la],ls[cn][la].push_back(i);
}
for(int i=1;i<=m;++i)
for(int j=0;j<=4;++j)
{
if(!a[i][j]) continue;
while(a[i][j]>1)
{
int xx=ls[i][j][a[i][j]-1],yy=ls[i][j][a[i][j]-2];
c1.push_back((node){xx,yy});
--a[i][j],--a[i][j];
ls[i][j].pop_back();
ls[i][j].pop_back();
}
if(a[i][j])
{
if(res[i]) c2.push_back((node){res[i],ls[i][j][0]}),res[i]=0;
else res[i]=ls[i][j][0];
}
}
int nn=c1.size(),mm=c2.size();
int ta=min((nn+mm)/2,nn);
printf("%d\n",ta);
while(ta--)
{
node st,en;
en=c1[nn-1];
--nn,c1.pop_back();
if(mm)
{
st=c2[mm-1];
--mm,c2.pop_back();
}
else
{
st=c1[nn-1];
--nn,c1.pop_back();
}
cout<<ss[st.x]<<" "<<ss[en.x]<<endl<<ss[st.y]<<" "<<ss[en.y]<<endl;
}
return 0;
}
D
题意
给一棵树,要找一个点作为根,使得对于同种深度的点,度数都相同
题解
容易发现这样的点要么是整棵树的重心(也就是样例解释的点\(3\)),要么是一个叶子,满足从这个叶子沿着对应的从树上伸出去链走,走到的第一个不在这条链上的点,在去掉那条链后变成剩下树的重心(同时满足条件)
也就是找到一个点,使得它作为根时其他儿子的子树都是满足条件且形态一样的树,或者有个儿子伸出去一条链.这个可以树哈希求出以某个点为根是子树的哈希值,然后换根dp求出子树以外的哈希值,就可以较方便的求解的
口胡一时爽,改题3h直接火葬场
#include<bits/stdc++.h>
#define db long double
#define uLL unsigned long long
using namespace std;
const int N=2e5+10;
int rd()
{
int x=0,w=1;char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int to[N<<1],nt[N<<1],hd[N],dg[N],tot=1;
void add(int x,int y)
{
++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot,++dg[x];
++tot,to[tot]=x,nt[tot]=hd[y],hd[y]=tot,++dg[y];
}
int n,sz[N],h[N],ans=-1;
uLL f[N],g[N],bs=99991,bb[N];
void dfs1(int x,int ffa)
{
if(dg[x]==1) h[x]=x;
bool o=1;
uLL pp=0;
sz[x]=1;
int szz=0,cn=0;
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==ffa) continue;
dfs1(y,x);
sz[x]+=sz[y];
if(!h[x]) h[x]=h[y];
if(!cn) szz=sz[y],pp=f[y];
else if(sz[y]!=szz||f[y]!=pp) o=0;
++cn;
}
o&=dg[x]==1||(bool)pp;
if(o)
{
while(cn--) f[x]=f[x]*bb[szz]+pp*szz;
f[x]=f[x]*bs+1;
}
else f[x]=0;
if(dg[x]>2) h[x]=0;
}
void dfs2(int x,int ffa)
{
bool o=1;
uLL p1=0,p2=0;
int s1=0,c1=0,s2=0,c2=0;
if(ffa)
{
p1=g[x],s1=n-sz[x],c1=1;
if(dg[x]<=2&&h[ffa]) h[x]=h[ffa];
}
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==ffa) continue;
if(!c1) p1=f[y],s1=sz[y],c1=1;
else if(f[y]==p1) ++c1;
else if(!c2) p2=f[y],s2=sz[y],c2=1;
else if(f[y]==p2) ++c2;
else o=0;
}
if(c1<c2||(c1==c2&&!p1)) swap(p1,p2),swap(s1,s2),swap(c1,c2);
o&=(bool)p1&(c2<=1);
if(o)
{
if(c1>1&&!c2)
{
printf("%d\n",x);
exit(0);
}
else
{
if(ffa&&g[x]==p2&&p2&&h[ffa]) {printf("%d\n",h[ffa]);exit(0);}
uLL nw=0;
bool o=c1==1;
while(c1--) nw=nw*bb[s1]+p1*s1;
nw=nw*bs+1;
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==ffa) continue;
if(f[y]==p2)
{
if(p2&&h[y]){printf("%d\n",h[y]);exit(0);}
g[y]=nw;
}
else if(o&&f[y]==p1) g[y]=p2?p2*s2*bs+1:0;
dfs2(y,x);
}
}
}
else
{
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==ffa) continue;
dfs2(y,x);
}
}
}
int main()
{
/*wdnmd*/
n=rd();
bb[0]=1;
for(int i=1;i<=n;++i)
{
bb[i]=bb[i-1]*bs;
}
for(int i=1;i<n;++i) add(rd(),rd());
if(n<=2) {puts("1");return 0;}
int rt=1;
while(dg[rt]==1) ++rt;
dfs1(rt,0);
dfs2(rt,0);
printf("%d\n",ans);
return 0;
}
E
题意
\(f_i=c^{2i-6}f_{i-1}f_{i-2}f_{i-3}(i>4)\)
已知\(n,f_1,f_2,f_3,c\),求\(f_n\)
题解
\(n\)很大,但是这个递推式很矩乘,考虑矩乘
矩乘就要记录每一项的指数,但是指数的模数是\(1e9+6\),不好直接做,可以把所有数改用\(\mod 1e9+6\)的原根表示,使用\(BSGS\)可以求出所有数对应的\(g^x\)的然后矩乘转移就完事了
\(x\),
wc我在干嘛
//嘤嘤嘤
#include<bits/stdc++.h>
#define db long double
#define il inline
#define re register
#define LL long long
using namespace std;
const int N=60,g=5;
LL rd()
{
LL x=0,w=1;char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int md=1e9+7,mod=md-1,nmd=500000003;
int fpow(int a,int b,int mod){int an=1;while(b){if(b&1) an=1ll*an*a%mod;a=1ll*a*a%mod,b>>=1;} return an;}
struct matrix
{
int a[9][9],n;
matrix(){memset(a,0,sizeof(a)),n=0;}
matrix operator * (const matrix &bb) const
{
matrix an;
an.n=n;
for(int i=0;i<n;++i)
for(int j=0;j<n;++j)
{
LL nw=0;
for(int k=0;k<n;++k) nw+=1ll*a[i][k]*bb.a[k][j];
an.a[i][j]=nw%mod;
}
return an;
}
matrix operator ^ (const LL &bb) const
{
matrix an,a=*this;
an.n=n;
for(int i=0;i<n;++i) an.a[i][i]=1;
LL b=bb;
while(b)
{
if(b&1) an=an*a;
a=a*a,b>>=1;
}
return an;
}
}aa,bb,cc,dd;
map<LL,LL> ha;
il LL bsgs(LL a,LL b,LL mod)
{
ha.clear();
LL kk=sqrt(mod)+1,aa=b,ka=fpow(a,kk,mod);
for(int i=0;i<kk;++i) ha[aa]=i,aa=aa*a%mod;
aa=1;
for(int i=0;i<=kk;++i)
{
if(ha.find(aa)!=ha.end()&&i*kk-ha[aa]>=0) return i*kk-ha[aa];
aa=aa*ka%mod;
}
return -1;
}
LL n,x,y,z,c,ans=1;
int main()
{
n=rd(),x=rd(),y=rd(),z=rd(),c=rd();
int xx=bsgs(g,x,md),yy=bsgs(g,y,md),zz=bsgs(g,z,md),ccc=1ll*bsgs(g,c,md)*2;
aa.n=bb.n=3;
aa.a[0][0]=xx,aa.a[0][1]=yy,aa.a[0][2]=zz;
bb.a[0][2]=1;
bb.a[1][0]=bb.a[1][2]=1;
bb.a[2][1]=bb.a[2][2]=1;
aa=aa*(bb^(n-3));
ans=1ll*ans*fpow(g,aa.a[0][2],md)%md;
cc.n=dd.n=5;
cc.a[0][3]=cc.a[0][4]=ccc;
dd.a[0][2]=1;
dd.a[1][0]=dd.a[1][2]=1;
dd.a[2][1]=dd.a[2][2]=1;
dd.a[3][3]=dd.a[3][2]=1;
dd.a[4][3]=dd.a[4][4]=1;
cc=(cc*(dd^(n-3)));
ans=1ll*ans*fpow(g,cc.a[0][2],md)%md;
cout<<ans<<endl;
return 0;
}
F
题意
求最小的整数\(x\in [a,b]\),使得\(|\sin(\frac{p}{q}\pi x)|\)最大
题解
妙蛙
由所学的高中数学可以知道,\(y=|\sin(x)|\)一个数\(x\)在\(\mod \pi\)时越接近\(\frac{\pi}{2}\)越大,在本题中就是求数\(x\),使得\(\frac{p}{q}\pi x\mod \pi\)最接近\(\frac{\pi}{2}\),这等价于要使得\(2px\mod 2q\)最接近\(q\).然后考虑分块,把\(t=\sqrt{b-a+1}\)作为块大小,设\(g(x)=2px\mod 2q\)然后预处理出二元组\((g(a),a),(g(a+1),a+1)...(g(a+t-1),a+t-1)\),按照\(g\)排序去重后就是一个\(g\)单调的序列,然后如果只查\([a,a+t-1]\)的话就可以直接二分找到最接近\(q\)的位置.然后现在每次把询问区间后移\(t\),假设现在是\([i,i+t-1]\),那么只要求出\(\mod 2q\)意义下最接近\(q- 2p(i-a) \mod 2q\)的位置即可.最后一些剩余部分暴力即可
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
using namespace std;
const int N=80000+10;
int rd()
{
int x=0,w=1;char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int l,r,n,p,q;
struct node
{
LL x;
int i;
bool operator < (const node &bb) const {return x!=bb.x?x<bb.x:i<bb.i;}
}a[N];
int main()
{
int T=rd();
a[0].x=-1;
while(T--)
{
int ans=0,mx=1<<30;
l=rd(),r=rd(),p=rd(),q=rd();
n=r-l+1;
int kk=sqrt(n),mod=2*q;
for(int i=0;i<kk;++i) a[i+1]=(node){2ll*p*(l+i)%mod,i};
sort(a+1,a+kk+1);
int m=0;
for(int i=1;i<=kk;++i)
if(a[i].x!=a[i-1].x) a[++m]=a[i];
int ii;
for(ii=l;ii+kk-1<=r;ii+=kk)
{
int zz=((1ll*q-2ll*p*(ii-l)%mod)%mod+mod)%mod;
int ps=upper_bound(a+1,a+m+1,(node){zz,0})-a,nw;
ps=(ps-1)%m+1;
nw=min(abs(1ll*a[ps].x-zz),min(abs(1ll*a[ps].x+mod-zz),abs(1ll*a[ps].x-mod-zz)));
if(mx>nw||(mx==nw&&ans>a[ps].i+ii)) ans=a[ps].i+ii,mx=nw;
ps=(ps+m-2)%m+1;
nw=min(abs(1ll*a[ps].x-zz),min(abs(1ll*a[ps].x+mod-zz),abs(1ll*a[ps].x-mod-zz)));
if(mx>nw||(mx==nw&&ans>a[ps].i+ii)) ans=a[ps].i+ii,mx=nw;
}
while(ii<=r)
{
int nw=abs(2ll*p*ii%mod-q);
if(mx>nw||(mx==nw&&ans>ii)) ans=ii,mx=nw;
++ii;
}
printf("%d\n",ans);
}
return 0;
}