T2 无论怎样神树大人都会删库跑路
注意暴力双端队列+桶计算时,一轮中可能对某个长为 的小串反复插入,会T。
判断字符串相同的条件比较特殊:每个数字出现次数相同则字符串相同。桶可以转成哈希——
进制的每一位系数分别表示这个位数的出现次数。
记录每个小串的整体哈希值,插入删除就是
的。
首先暴力前几轮(一轮指的是完整的 次操作),使得小串连接总长 ,后面每轮都是等价的,再多进行一轮算一下每次操作的贡献即可。
#include<bits/stdc++.h>
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define sc second
#define gc getchar
#define pb push_back
using namespace std;
const int N=1e5+10,p1=1e9+7,p2=1e9+9,bs=1e5+7;
typedef long long ll;
typedef double db;
int n,T,q,m,R[N],sz[N],a[N];
int r[N],gx[N],rnd,L,t[N];
pii pw[N],ori,v,nw;ll ans,whl;
vector<pii>hz[N];
char cp;
inline int rd()
{
cp=gc();int x=0,f=1;
for(;!isdigit(cp);cp=gc()) if(cp=='-') f=-1;
for(;isdigit(cp);cp=gc()) x=x*10+(cp^48);
return f*x;
}
inline int ad(int x,int y,int p){x+=y;return x>=p?x-p:x;}
inline int dc(int x,int y,int p){x-=y;return x<0?x+p:x;}
inline pii operator *(pii a,int b){return mkp((ll)a.fi*b%p1,(ll)a.sc*b%p2);}
inline pii operator +(pii a,int b){return mkp(ad(a.fi,b,p1),ad(a.sc,b,p2));}
inline pii operator +(pii a,pii b){return mkp(ad(a.fi,b.fi,p1),ad(a.sc,b.sc,p2));}
inline pii operator -(pii a,pii b){return mkp(dc(a.fi,b.fi,p1),dc(a.sc,b.sc,p2));}
inline pii operator *(pii a,pii b){return mkp((ll)a.fi*b.fi%p1,(ll)a.sc*b.sc%p2);}
struct P{int id,len;}tp;
deque<P>que;
inline void upd(int x)
{
nw=nw+hz[x][sz[x]];L+=sz[x];
que.push_back((P){x,sz[x]});
for(;L>T;){
tp=que.front();que.pop_front();nw=nw-hz[tp.id][tp.len];
if(L-tp.len>=T) L-=tp.len;else{
nw=nw+hz[tp.id][T-L+tp.len];
que.push_front((P){tp.id,T-L+tp.len});L=T;
}
}
}
int main(){
int i,j,x,y,mx=0;pw[0]=mkp(1,1);
for(i=1;i<N;++i) pw[i]=pw[i-1]*bs;
n=rd();T=rd();q=rd();
for(i=1;i<=T;++i) ori=ori+pw[rd()+1];
for(i=1;i<=n;++i){
sz[i]=x=rd();hz[i].resize(x+1);v.fi=v.sc=0;
for(j=1;j<=x;++j) {a[j]=rd()+1;v=v+pw[a[j]];}
for(j=x;j>0;--j) {hz[i][j]=v;v=v-pw[a[x-j+1]];}
}
for(m=rd(),i=1;i<=m;++i) whl+=sz[(r[i]=rd())];
rnd=((T-1)/whl+1)*m;
for(i=1;i<=q && i<=rnd;++i){upd(r[(i-1)%m+1]);ans+=(L==T && ori==nw);}
for(i=1;i<=m && rnd+i<=q;++i){upd(r[(i-1)%m+1]);gx[i]=gx[i-1]+(ori==nw);}
if(q>rnd) ans+=(ll)gx[m]*((q-rnd)/m)+gx[q%m];
printf("%lld",ans);
return 0;
}
T3 OwenOwl 不学车也不删库
神仙构造题还是不会做 (*  ̄︿ ̄)
官方题解:
数形结合,不妨将原图看做一维直线上的模 意义下的 个点 , 的拓展相当于拓展到了模 意义下的 维空间中(一共 )个点,让原图中的每个点对应空间中的一个点。
枚举一个非零向量
和起点
,
分为一组即可。
两个不同点唯一确定剩下的
个点,且由于
为质数,一定有解。
std
#include<bits/stdc++.h>
#define pb push_back
#define gc getchar
using namespace std;
const int N=2010;
typedef long long ll;
typedef double db;
int n=1,p,k,dlt,q[N];
bool g[N][N];
inline int cal(int x,int y)
{
int re=0,i,j,pw=1;
for(i=0;i<k;++i,pw*=p,x/=p,y/=p)
re+=(p+x%p+y%p)%p*pw;
return re;
}
int main(){
int i,j,x,y;
scanf("%d%d",&p,&k);puts("YES");
for(i=1;i<=k;++i) n*=p;
for(i=0;i<n;++i)
for(j=i+1;j<n;++j) if(!g[i][j]){
dlt=cal(j,-i);q[0]=i;
for(x=1;x<p;++x) q[x]=cal(q[x-1],dlt);
for(x=0;x<p;++x){
printf("%d ",q[x]);
for(y=0;y<p;++y)
g[q[x]][q[y]]=true;
}
putchar('\n');
}
return 0;
}
T4 总而言之神J要去练习篮球
万古神犇mcfx,扑通扑通跪下来。
这题好神…膜了一发官方题解
为方便处理,每个询问 转化为四个左上角为 的矩阵的贡献和
首先考虑
的情况:
问题转换为了,对于
,求
有多少种取值,以及每种值的出现次数。
对于每个特定的 ,数位 枚举 与 第一次分开的位求解 :
int cal(int r1,int r2,int x){
int R=r1^r2;
int ans=0;
for(int i=30;i>=0;--i){
if(((r1>>i&1)||(r2>>i&1))){
int a=r1>>i&1,b=r2>>i&1,c=x>>i&1;
int d=(1<<i);
if(a&&(b==c))ans+=r2%d+1;
if(b&&(a==c))ans+=r1%d+1;
if(a&&b&&0==c)ans+=d;
}
if((x>>i&1)!=(R>>i&1))break;
}
return ans+(x==R);
}
发现不同的 只是 的位不同(即和 第一个不同的位不同),所以问题总复杂度也是 的。
再考虑 的情况,怎么把它转化成 的情况呢?
考虑行列差分,此时左上角分别为 的矩阵相同的条件:
- , 同理
由于 ,所以实际上就是判断
发现在
不断
的过程中,会影响到的二进制位有
,等价于
的最高位,设其为
。
序列相等,则必须满足后
位相同,相当于是一个
的循环节。
同理。
枚举每个行循环节
,列循环节
所对应的行列
那么问题就变成了求解
的值的种类数和对应出现次数。
进一步还可以得到结论:
枚举到
时,可以强制行列循环节均为
。
因为一侧不同,另一侧改变时,异或值一定不同,所以可以分开统计。
问题相当于枚举行列末 位相同,再套上 的情况计算。
复杂度
对着std抄了一遍
#include<bits/stdc++.h>
typedef long long ll;
#define pii pair<ll,ll>
#define mkp make_pair
#define fi first
#define sc second
#define gc getchar
#define pb push_back
using namespace std;
const int mod=1e9+7;
typedef double db;
int tk,W,H,K,ans;
vector<pii>a;
inline void ad(int &x,int y){x+=y;if(x>=mod) x-=mod;}
inline int fp(int x,int y)
{
int re=1;
for(;y;y>>=1,x=(ll)x*x%mod)
if(y&1) re=(ll)re*x%mod;
return re;
}
/*single point*/
inline void mk(vector<pii>&v,int l,int r,ll vl)
{if(vl){v.pb(mkp(l,vl));v.pb(mkp(r,-vl));}}
//模拟数位DP 枚举所有数
void mat(int x,int y,vector<pii>&v,int pr)
{
if(x<0 || y<0) return;
int a,b,c,d,i,R=(x^y),res=0;
ll ss=0,rss;
for(i=30;i>=0;--i){
//枚举第一次分离的位
rss=ss;d=1<<i;a=x&d;b=y&d;c=(R&d)^d;
if(a&&(b==c)) rss+=(y%d)+1;
if(b&&(a==c)) rss+=(x%d)+1;
if(a&&b&&(c==0)) rss+=d;
res|=(R&d);
mk(v,res^d,(res^d)+d,pr*rss);c^=d;
if(a&&(b==c)) ss+=(y%d)+1;
if(b&&(a==c)) ss+=(x%d)+1;
if(a&&b&&(c==0)) ss+=d;
}
mk(v,res,res+1,pr*(ss+1));
}
void Single_sol(int lx,int rx,int ly,int ry,ll cnt)
{
if(lx>rx || ly>ry) return;
vector<pii>re;int i,sz;ll ss=0;
mat(rx,ry,re,1);mat(lx-1,ry,re,-1);mat(rx,ly-1,re,-1);mat(lx-1,ly-1,re,1);
sort(re.begin(),re.end());sz=re.size();
for(i=0;i<sz;++i){
ss+=re[i].sc;
if(ss && i+1<sz && re[i+1].fi>re[i].fi) a.pb(mkp(ss,cnt*(re[i+1].fi-re[i].fi)%mod));
}
}
/* step by step (2^k)*/
struct P{ll d;int l,r;};
inline void ins(int l,int r,int ql,int qr,vector<P>&v)
{if(l<=r && ql<=qr) v.pb((P){r-l+1,ql,qr});}
inline void nd(int lx,int rx,int liml,int limr,int stp,vector<P>&v)
{
int L=max(lx%stp,liml),R=min(rx%stp,limr),l=lx/stp,r=rx/stp;
if(L<=R){
ins(liml,L-1,l+1,r,v);
ins(L,R,l,r,v);
ins(R+1,limr,l,r-1,v);
}else{
ins(liml,R,l+1,r,v);
ins(max(liml,R+1),min(limr,L-1),l+1,r-1,v);
ins(L,limr,l,r-1,v);
}
}
//x*2^k xor y*2^k = X
inline void Step_sol(int lx,int rx,int ly,int ry,int llx,int lrx,int lly,int lry,int k)
{
if(llx>lrx || lly>lry) return;
vector<P>ra,rb;
nd(lx,rx,llx,lrx,1<<k,ra);nd(ly,ry,lly,lry,1<<k,rb);
for(P a:ra)
for(P b:rb)
Single_sol(a.l,a.r,b.l,b.r,a.d*b.d%mod);
}
/*major*/
void sol(int lx,int rx,int ly,int ry)
{
if(W==1 && H==1) {Single_sol(lx,rx,ly,ry,1);return;}
rx=rx-W+1;ry=ry-H+1;int c=0,L=1;
for(;L<W || L<H;L<<=1) c++;//max( 0^(W-1) | 0^(H-1) ) 共c位 循环节 2^c
Step_sol(lx,rx,ly,ry,0,L-W,0,L-H,c);
for(c++;c<=30;L<<=1,c++){
Step_sol(lx,rx,ly,ry,L-W+1,L-1,0,(L<<1)-H,c);// 0->(L<<1)-H 所有xor <2^(c+1)的数
//L-W+1 -> L-1 注意只能算一次
Step_sol(lx,rx,ly,ry,0,L-W,L-H+1,L-1,c);
Step_sol(lx,rx,ly,ry,L,(L<<1)-W,L-H+1,L-1,c);
}
}
int main(){
int i,j,sz,lx,ly,rx,ry;
for(scanf("%d",&tk);tk;--tk){
a.clear();ans=0;
scanf("%d%d%d%d%d%d%d",&lx,&rx,&ly,&ry,&W,&H,&K);
sol(lx,rx,ly,ry);
sort(a.begin(),a.end());sz=a.size();
for(i=0;i<sz;++i){
if((!i)||(a[i].fi!=a[i-1].fi)) j=fp(a[i].fi%mod,K);
ad(ans,(ll)j*a[i].sc%mod);
}
printf("%d\n",(ll)ans*fp((ll)(rx-lx-W+2)*(ry-ly-H+2)%mod,mod-1-K)%mod);//注意是-k次幂(k^(mod-2)) 不是mod-2+k
}
return 0;
}