題意:n個節點的樹,每個點有一個顏色,詢問點u子樹中距離不超過d的節點有多少種不同的顏色
題解:按深度依次插入節點u,用set維護它dfs序相鄰的同色點l,r,
再對每一個深度開一個動態開點線段樹,把u對應的dfs序位置 u+1,LCA(u,l)-1,LCA(u,r)-1,LCA(l,r)+1
實際上就是一個lca去重,查詢的時候直接查dep[u]+d對應深度的線段樹中u子樹對應的區間
代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
#define N 100005
int col[N],fir[N],to[2*N],nxt[2*N],cnt;
void adde(int a,int b)
{
to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;
to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;
}
int fa[N],son[N],top[N],siz[N],dep[N],dfn[N],num[N],dc;
vector<int> G[N];int mxd;
void dfs1(int u)
{
dep[u]=dep[fa[u]]+1;siz[u]=1;
mxd=max(mxd,dep[u]);
G[dep[u]].push_back(u);
for(int v,p=fir[u];p;p=nxt[p]){
if((v=to[p])!=fa[u]){
fa[v]=u;dfs1(v);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v])
son[u]=v;
}
}
}
void dfs2(int u)
{
dfn[u]=++dc;num[dc]=u;
if(son[u])top[son[u]]=top[u],dfs2(son[u]);
for(int v,p=fir[u];p;p=nxt[p])
if((v=to[p])!=fa[u]&&v!=son[u])
top[v]=v,dfs2(v);
}
int LCA(int x,int y)
{
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
set<int> S[N];
set<int>::iterator it1,it2,edi;
struct node{
int l,r,x;
}a[N<<5];
int T[N],tot;
void insert(int &i,int l,int r,int x,int k,int pre)
{
if(i==pre)i=++tot,a[i]=a[pre];
a[i].x+=k;
if(l==r)return;
int mid=(l+r)>>1;
if(x<=mid)insert(a[i].l,l,mid,x,k,a[pre].l);
else insert(a[i].r,mid+1,r,x,k,a[pre].r);
}
int query(int i,int l,int r,int ql,int qr)
{
if(ql>r||l>qr)return 0;
if(ql<=l&&r<=qr)return a[i].x;
int mid=(l+r)>>1;
return query(a[i].l,l,mid,ql,qr)+query(a[i].r,mid+1,r,ql,qr);
}
int main()
{
int Tes,i,j,n,m,u,l,r,d;
scanf("%d",&Tes);
while(Tes--){
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)scanf("%d",&col[i]);
for(i=2;i<=n;i++){scanf("%d",&u);adde(u,i);}
dc=mxd=0;
dfs1(1);top[1]=1;dfs2(1);
for(i=1;i<=mxd;i++){
T[i]=T[i-1];
for(j=0;j<int(G[i].size());j++){
u=G[i][j];l=r=0;
it1=it2=S[col[u]].lower_bound(dfn[u]);
if(it1!=S[col[u]].begin())it1--,l=num[*it1];
edi=S[col[u]].end();
if(it2!=edi)r=num[*it2];
insert(T[i],1,dc,dfn[u],1,T[i-1]);
if(l)
insert(T[i],1,dc,dfn[LCA(u,l)],-1,T[i-1]);
if(r)
insert(T[i],1,dc,dfn[LCA(u,r)],-1,T[i-1]);
if(l&&r)
insert(T[i],1,dc,dfn[LCA(l,r)],1,T[i-1]);
S[col[u]].insert(dfn[u]);
}
}
int las=0;
for(i=1;i<=m;i++){
scanf("%d%d",&u,&d);
u^=las;d^=las;
int nd=min(mxd,d+dep[u]);
las=query(T[nd],1,dc,dfn[u],dfn[u]+siz[u]-1);
printf("%d\n",las);
}
cnt=0;tot=0;
for(i=1;i<=n;i++){
fir[i]=0;
S[col[i]].clear();
dfn[i]=num[i]=0;
siz[i]=fa[i]=son[i]=top[i]=dep[i]=0;
}
for(i=1;i<=mxd;i++)G[i].clear(),T[i]=0;
}
}
題意:一棵n個點的樹,求選出任意兩點,其距離爲質數的概率
題解:點分治+FFT版題,子樹去重一下即可
代碼:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
inline int gi()
{
char c;int num=0,flg=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
return num*flg;
}
#define N 100005
int n;
int prime[N],tot;
bool pvis[N];
void shai()
{
int i,j;pvis[1]=1;
for(i=2;i<=n;i++){
if(!pvis[i])prime[++tot]=i;
for(j=1;j<=tot;j++){
int tmp=i*prime[j];
if(tmp>n)break;
pvis[tmp]=1;
if(i%prime[j]==0)break;
}
}
}
int fir[N],to[2*N],nxt[2*N],cnt;
void adde(int a,int b)
{
to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;
to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;
}
int tmpsiz[N],nrt,all;
bool vis[N];
void findrt(int u,int ff)
{
tmpsiz[u]=1;int mx=0;
for(int v,p=fir[u];p;p=nxt[p]){
if((v=to[p])!=ff&&!vis[v]){
findrt(v,u);
tmpsiz[u]+=tmpsiz[v];
mx=max(mx,tmpsiz[v]);
}
}
mx=max(mx,all-tmpsiz[u]);
if(2*mx<=all)nrt=u;
}
int getrt(int u,int sz)
{
all=sz;nrt=-0x3f3f3f3f;
findrt(u,0);return nrt;
}
struct cp{
double r,i;
cp(){}
cp(double x,double y){r=x;i=y;}
cp operator + (const cp &t){return cp(r+t.r,i+t.i);}
cp operator - (const cp &t){return cp(r-t.r,i-t.i);}
cp operator * (const cp &t){return cp(r*t.r-i*t.i,r*t.i+i*t.r);}
}w,wn;
int rev[N];
const double PI=3.14159265358979323846264338;
void FFT(vector<cp> &a,int len,int flg)
{
int i,j,k;
for(i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|((i&1)*(len>>1));
for(i=0;i<len;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
for(i=1;i<len;i<<=1){
wn=cp(cos(PI/i),sin(PI/i));
if(flg==-1)wn.i=-wn.i;
for(j=0;j<len;j+=(i<<1)){
w=cp(1,0);
for(k=j;k<i+j;k++){
cp u=a[k],v=a[k+i]*w;
a[k]=u+v;
a[k+i]=u-v;
w=w*wn;
}
}
}
if(flg==-1)
for(i=0;i<len;i++)
a[i].r/=len;
}
vector<cp> a,c;
void pre(int u,int ff,int d)
{
tmpsiz[u]=1;
while(d>=(int)a.size())a.push_back(cp(0,0));
a[d].r++;
for(int v,p=fir[u];p;p=nxt[p]){
if(!vis[v=to[p]]&&v!=ff){
pre(v,u,d+1);
tmpsiz[u]+=tmpsiz[v];
}
}
}
long long ans;
void update(vector<cp> &a,int flg)
{
c.clear();int len=1;
while(len<2*(int)a.size())len<<=1;
while((int)a.size()<len)a.push_back(cp(0,0));
while((int)c.size()<len)c.push_back(cp(0,0));
FFT(a,len,1);
for(int i=0;i<len;i++)c[i]=a[i]*a[i];
FFT(c,len,-1);
for(int i=2;i<len;i++)if(!pvis[i])
ans=ans+1ll*flg*(long long)(c[i].r+0.5);
}
void DFZ(int u)
{
vis[u]=1;
a.clear();pre(u,0,0);
update(a,1);
for(int v,p=fir[u];p;p=nxt[p])
if(!vis[v=to[p]]){
a.clear();pre(v,u,1);
update(a,-1);
}
for(int v,p=fir[u];p;p=nxt[p])
if(!vis[v=to[p]])DFZ(getrt(v,tmpsiz[v]));
}
int main()
{
//freopen("1.in","r",stdin);
//freopen("WA.out","w",stdout);
int i,u,v;
n=gi();shai();
for(i=1;i<n;i++){u=gi();v=gi();adde(u,v);}
DFZ(getrt(1,n));
ans/=2;
printf("%.6f\n",(double)ans/((long long)n*(n-1)/2));
}
題意:給一個n個點的樹與一個長度爲n的排列a,每次修改交換排列上相鄰的兩個數, 每次詢問給出l,r,v,求al~ar每個點到v的距離和
題解:可持久化點分樹
像之前那道題一樣做的話時間空間都是無法承受的
考慮到如果可以維護出a1~ai的點分樹(每個點分中心維護a的前綴點集到它的距離和以及它點分區域包含點的個數)
那麼我們可以直接差分得到答案了
於是,可持久化點分樹就誕生了,每次加入一個點就對應修改點分樹上的一條鏈
但是事與願違,我們對於每個點分中心還要保存它兒子的信息來去重,而如果是菊花圖就會把可持久化點分樹卡到n^2
所以我們還需要把原樹進行三度化
代碼:(細節過多引起極度不適)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
char c;int num=0,flg=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
return num*flg;
}
#define N 400005
int n,m,P[N];
int fir[N],to[2*N],nxt[2*N],cd[2*N],cnt,du[N];
void adde(int a,int b,int c)
{
to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;cd[cnt]=c;
to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;cd[cnt]=c;
du[a]++;du[b]++;
}
struct node{
int u,v,w;
node(){}
node(int x,int y,int z){u=x;v=y;w=z;}
}e[N];int ecnt;
void sandu(int u,int ff)
{
int pre=u;
for(int v,p=fir[u];p;p=nxt[p]){
v=to[p];if(v==ff)continue;
if(du[u]-bool(ff)>=3){
e[++ecnt]=node(pre,++n,0);
e[++ecnt]=node(n,v,cd[p]);
pre=n;
}
else e[++ecnt]=node(u,v,cd[p]);
sandu(v,u);
}
}
bool vis[N];
int tmpsiz[N],all,nrt;
void findrt(int u,int ff)
{
tmpsiz[u]=1;int mx=0;
for(int v,p=fir[u];p;p=nxt[p]){
if((v=to[p])!=ff&&!vis[v]){
findrt(v,u);
tmpsiz[u]+=tmpsiz[v];
mx=max(mx,tmpsiz[v]);
}
}
mx=max(mx,all-tmpsiz[u]);
if(2*mx<=all)nrt=u;
}
int getrt(int u,int sz)
{
all=sz;nrt=-0x3f3f3f3f;
findrt(u,0);return nrt;
}
#define LOG 20
#define LL long long
LL dis[LOG][N];int from[LOG][N],dep[N];
int id[N*LOG],ch[N*LOG][4],T[N],tot;
LL sum[N*LOG],fsum[N*LOG],con[N*LOG];
void pre(int u,int ff,int d)
{
tmpsiz[u]=1;
for(int v,p=fir[u];p;p=nxt[p]){
if(!vis[v=to[p]]&&v!=ff){
dis[d][v]=dis[d][u]+1ll*cd[p];
pre(v,u,d);
tmpsiz[u]+=tmpsiz[v];
}
}
}
void DFZ(int u,int d)
{
dep[u]=d;id[u]=u;
vis[u]=1;pre(u,0,d);
for(int v,p=fir[u],so=0;p;p=nxt[p]){
if(!vis[v=to[p]]){
v=getrt(v,tmpsiz[v]);
ch[u][so]=v;from[d][v]=so;so++;
for(int i=0;i<d;i++)
from[i][v]=from[i][u];
DFZ(v,d+1);
}
}
}
void insert(int &u,int x)
{
id[++tot]=id[u];sum[tot]=sum[u];fsum[tot]=fsum[u];con[tot]=con[u];
for(int i=0;i<=2;i++)ch[tot][i]=ch[u][i];u=tot;
int d=dep[id[u]];
sum[u]+=dis[d][x];con[u]++;
if(d)fsum[u]+=dis[d-1][x];
if(id[u]==x)return;
insert(ch[u][from[d][x]],x);
}
LL query(int u,int x)
{
if(!u)return 0ll;
LL ret=sum[u]+con[u]*dis[0][x];
for(int i=1;i<=dep[x];i++){
u=ch[u][from[i-1][x]];
ret+=sum[u]+con[u]*dis[i][x];
ret-=fsum[u]+con[u]*dis[i-1][x];
}
return ret;
}
int main()
{
int u,v,w,i,tn,op,l,r,x;
tn=n=gi();m=gi();
for(i=1;i<=n;i++)P[i]=gi();
for(i=1;i<n;i++){u=gi();v=gi();w=gi();adde(u,v,w);}
sandu(1,0);
cnt=0;memset(fir,0,sizeof(fir));
for(i=1;i<=ecnt;i++)adde(e[i].u,e[i].v,e[i].w);
DFZ(T[0]=getrt(1,n),0);tot=n;
for(i=1;i<=tn;i++)
insert(T[i]=T[i-1],P[i]);
LL ans=0;
for(i=1;i<=m;i++){
op=gi();
if(op==1){
l=gi();r=gi();x=gi();
l^=ans;r^=ans;x^=ans;
ans=query(T[r],x)-query(T[l-1],x);
printf("%lld\n",ans);
ans=ans%(1<<30);
}
else{
x=gi();x^=ans;
swap(P[x],P[x+1]);
insert(T[x]=T[x-1],P[x]);
}
}
}
[JZOJ5520]Every one will meet some difficult
https://blog.csdn.net/hzj1054689699/article/details/85857283
考慮組合意義,利用生成函數將式子化爲卷積形式,再暴力卷積+快速冪即可
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1005
#define LL long long
const int mod=1000109107;
int lim;
struct node{
int a[N];
node(){memset(a,0,sizeof(a));}
node operator * (const node &t)const{
node c;
for(int i=0;i<lim;i++)
for(int j=0;i+j<lim;j++)
c.a[i+j]=(c.a[i+j]+1ll*a[i]*t.a[j])%mod;
return c;
}
node operator ^ (LL y)const{
node ret,x=*this;ret.a[0]=1;
while(y){
if(y&1)ret=ret*x;
y>>=1;x=x*x;
}
return ret;
}
}a,b;
int main()
{
int i,j;LL s,t,n,m;
scanf("%lld%lld%lld%lld",&s,&t,&n,&m);
lim=m-n+2;
a.a[0]=a.a[1]=b.a[0]=b.a[1]=1;
a=a^t;b=b^(s-n*t);
for(i=0;i<lim;i++)a.a[i]=a.a[i+1];
a=a^n;a=a*b;
printf("%d",a.a[m-n]);
}
20200518魚貫而入
題意:給出n個數,求一個hash表的大小len,使這n個數撞hash的次數最多,輸出撞hash的次數。
(這裏的hash表是:如果y=x%len撞了hash,那麼就把y放到y+1位置(如果繼續撞就再+1))
n<=200
題解:亂搞題
先暴力驗證一下小範圍的len,再n個數任選兩個做差,驗證一下差的所有因子
這裏的差可能比較大,PR一下即可
代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
#define N 205
#define LL long long
int nn,ans;LL a[N];
map<LL,LL> h;
void add_fish(int &cnt,LL x,LL len)
{
LL y=x%len;
while(h.count(y)&&h[y]!=x)y=(y+1)%len,cnt++;
h[y]=x;
}
//#include<ctime>
//double sum;
void solve(LL len)
{
//double c1=clock();
h.clear();int cnt=0,i;
for(i=1;i<=nn;i++) add_fish(cnt,a[i],len);
//if(cnt>ans)printf("%lld\n",len);
ans=max(cnt,ans);
//sum+=clock()-c1;
}
inline LL mul(LL a,LL b,LL p){return (a*b-(LL)((long double)a*b/p)*p+p)%p;}
LL ksm(LL x,LL y,LL mod)
{
LL ans=1;
while(y){
if(y&1) ans=mul(ans,x,mod);
y>>=1;x=mul(x,x,mod);
}
return ans;
}
bool MR(LL n)
{
if(n==2) return 1;
if(n<2||!(n&1)) return 0;
LL m=n-1;int i,j,k=0;
while(!(m&1)){k++;m>>=1;}
for(i=0;i<10;i++){
LL a=rand()%(n-1)+1,x=ksm(a,m,n),y=0;
for(j=0;j<k;j++){
y=mul(x,x,n);
if(y==1&&x!=1&&x!=n-1) return 0;
x=y;
}
if(y!=1) return 0;
}
return 1;
}
LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
LL Rho(LL n,LL c)
{
LL x=rand()%n+1,y=x,q=1,d=1,k=1;
while(1){
for(int i=1;i<=k;i++){
x=(mul(x,x,n)+c)%n;
q=mul(q,abs(x-y),n);
if(!(i&127)&&(d=gcd(q,n))>1) break;
}
if(d>1||(d=gcd(q,n))>1)
return d==n?Rho(n,c+1):d;
k<<=1;q=1;y=x;
}
}
//int con;
void Pollar(LL n)
{
if(n==1) return;
if(MR(n)){if(n>2000)solve(n);return;}
LL p=Rho(n,3);
while(n%p==0) n/=p;
Pollar(p);Pollar(n);
}
int main()
{
//freopen("3.in","r",stdin);
//double c1=clock();
srand(0);
int tp,i,j;
scanf("%d%d",&tp,&nn);
for(i=1;i<=nn;i++)scanf("%lld",&a[i]);
for(i=nn;i<=2000;i++)solve(i);
sort(a+1,a+nn+1);
for(i=2;i<=nn;i++){
int tt=min(i-1,10);
while(tt--){
j=rand()%(i-1)+1;
Pollar(a[i]-a[j]);
}
}
//printf("%d\n",con);
//printf("%.3f\n",sum/1000);
printf("%d\n",ans);
//printf("%.3fs\n",(clock()-c1)/1000);
}
小P的畫
論文題
過於毒瘤,題解咕咕咕了
代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N (1<<15)+1
#define LL long long
const int mod=998244353;
int con[N],lg[N],pw3[16];LL pw2[61];
int w[N],g[N],st[N],f[14348907];bool pd[N];
LL a[16];int rk[16],id[16];
bool cmp(int x,int y){return a[x]<a[y];}
int cnt;LL ta[N];int dp[2][2];
int solve(LL C)
{
if(C>ta[cnt]&&(C^ta[cnt])>ta[cnt])return 0;
if(ta[cnt]==0)return 1;
LL X=1ll<<(upper_bound(pw2,pw2+60,ta[cnt])-pw2-1);
dp[0][0]=dp[0][1]=dp[1][0]=dp[1][1]=0;
int now=0;
dp[now][0]=1;
for(int i=1;i<cnt;i++){
dp[now^1][0]=dp[now^1][1]=0;
if(ta[i]>=X){
dp[now^1][0]=(1ll*X%mod*dp[now][0]+1ll*(ta[i]-X+1)%mod*dp[now][1])%mod;
dp[now^1][1]=(1ll*X%mod*dp[now][1]+1ll*(ta[i]-X+1)%mod*dp[now][0])%mod;
}
else{
dp[now^1][0]=1ll*(ta[i]+1)%mod*dp[now][0]%mod;
dp[now^1][1]=1ll*(ta[i]+1)%mod*dp[now][1]%mod;
}
now^=1;
}
int ret;
if(C>=X)ret=dp[now][1];
else ret=dp[now][0];
ta[cnt]^=X;C^=X;
for(int i=cnt;i>1;i--){
if(ta[i]<ta[i-1])swap(ta[i],ta[i-1]);
else break;
}
return (ret+solve(C))%mod;
}
bool e[16][16];
int main()
{
int n,m,all,al3,i,s,t,u,v;LL C;
scanf("%d%d%lld",&n,&m,&C);
all=1<<n;
for(i=0;i<n;i++)scanf("%lld",&a[i]),id[i]=i;
sort(id,id+n,cmp);sort(a,a+n);
for(i=0;i<n;i++)rk[id[i]]=i;
lg[0]=-1;
for(s=1;s<all;s++){
lg[s]=lg[s>>1]+1;
con[s]=con[s>>1]+(s&1);
}
pw2[0]=1;pw3[0]=1;
for(i=1;i<=60;i++)pw2[i]=2ll*pw2[i-1];
for(i=1;i<=n;i++)pw3[i]=3*pw3[i-1];
al3=pw3[n];
for(i=1;i<=m;i++){
scanf("%d%d",&u,&v);
if(u>v)swap(u,v);e[u][v]=1;
u=rk[u-1];v=rk[v-1];
pd[(1<<u)|(1<<v)]=1;
}
for(i=0;i<n;i++)for(s=0;s<all;s++)
if(s&(1<<i))pd[s]|=pd[s^(1<<i)];
for(s=1;s<all;s++){
w[s]=!pd[s];// \sum_{i=0}^{Ecnt[s]} C(Ecnt[s],i)*(-1)^i=0^(Ecnt[s])
for(t=(s-1)&s;t;t=(t-1)&s)if(t&(s&-s))
w[s]=(w[s]-w[t]*(!pd[s^t]))%mod;
}
for(s=1;s<all;s++)if(!(con[s]&1))w[s]=1ll*(a[lg[s&-s]]+1)%mod*w[s]%mod;
for(s=1;s<all;s++){
cnt=0;
for(i=0;i<n;i++)if(s&(1<<i))
ta[++cnt]=a[i];
g[s]=solve(C);
}
for(s=1;s<all;s++)st[s]=st[s>>1]*3+(s&1);
for(s=1;s<all;s++)if(con[s]&1)st[s]+=pw3[lg[s&-s]];
f[0]=1;if(C==0)g[0]=1;
int ans=0;
for(s=0;s<al3;s++)if(f[s]){
int flg=0,s0=0;
for(i=0;i<n;i++)if(s/pw3[i]%3==0)s0|=1<<i;
if(s0){
flg=(s0&-s0);s0-=flg;
for(t=s0;;t=(t-1)&s0){
int tmp=s+st[t+flg];
f[tmp]=(1ll*f[tmp]+1ll*f[s]*w[t+flg])%mod;
if(!t)break;
}
}
else{
int s2=0;
for(i=0;i<n;i++)if(s/pw3[i]%3==2)s2|=1<<i;
ans=(1ll*ans+1ll*f[s]*g[s2])%mod;
}
}
printf("%d\n",(ans+mod)%mod);
}
20200521river
n<=10^9,m<=10^6
題解:貪心
先求出每種天氣下到達下一個地點的最少天數,我們一定是每次都選擇最少天數的方法去走
於是我們可以建出一個有向圖,且帶有一個環,跟Pollard_Rho中的Rho很像的
先算一下環外鏈的權值,再算一下環的權值
我們如果走完了環外了鏈,就會到環上轉圈圈
環權值乘上我們轉的圈數就是我們轉圈的代價,如果還沒有到達目的地,就再手動把剩下的幾步加上
代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
char c;int num=0,flg=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
return num*flg;
}
#define N 1000005
#define LL long long
const LL INF=0x3f3f3f3f3f3f3f3fll;
int a[N],dfn[N],cnt,fir,len;LL g[N];bool vis[N];
int main()
{
int n,m,i,j;
LL pre=INF,suf=INF,ans=0,sum=0;
n=gi();m=gi();
for(i=0;i<m;i++)a[i]=gi(),g[i]=INF;
for(i=1;i<m;i++)pre=min(pre,1ll*a[i-1]+i-1),g[i]=min(g[i],pre+1ll*m-1ll*i);
for(i=m-1;i>=0;i--)suf=min(suf,1ll*a[i]+i),g[i]=min(g[i],suf-1ll*i);
for(i=0;!vis[i];i=(i+g[i])%m)
vis[i]=1,dfn[++cnt]=i;
fir=i;
for(i=1;dfn[i]!=fir&&i<=cnt;i++)
ans+=g[dfn[i]],n--;
if(n>0){
for(j=i;j<=cnt;j++)sum+=g[dfn[j]];
ans+=n/(cnt-i+1)*sum;n%=(cnt-i+1);
for(j=i;n;j++,n--)ans+=g[dfn[j]];
}
printf("%lld\n",ans);
}
20200521cac
題解:圓方樹+樹狀數組,把方點與圓點的貢獻分開來計算,方點用樹狀數組統計,圓點就直接加權值
代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
inline int gi()
{
char c;int num=0,flg=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
return num*flg;
}
#define N 600005
#define M 1000005
int fir[N],nxt[2*N],to[2*N],cnt;
void adde(int a,int b)
{
to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;
to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;
}
int dfn[N],low[N],stk[N],tp,dc,pbccnt;
vector<int> pbc[N];
void dfs(int u,int fa)
{
dfn[u]=low[u]=++dc;
stk[tp++]=u;
int v,p;
for(p=fir[u];p;p=nxt[p]){
v=to[p];
if(!dfn[v]){
dfs(v,u);low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]){
pbccnt++;
while(tp>0){
pbc[pbccnt].push_back(stk[--tp]);
if(stk[tp]==v)
break;
}
pbc[pbccnt].push_back(u);
}
}
else if(v!=fa) low[u]=min(low[u],dfn[v]);
}
}
int fa[N],dep[N],son[N],siz[N],top[N];
void dfs1(int u)
{
dep[u]=dep[fa[u]]+1;
int v,p;siz[u]=1;
for(p=fir[u];p;p=nxt[p]){
v=to[p];
if(v!=fa[u]){
fa[v]=u;dfs1(v);siz[u]+=siz[v];
if(siz[son[u]]<siz[v])
son[u]=v;
}
}
}
const int mod=998244353;
int pos[N],ddfn;
void dfs2(int u)
{
pos[u]=++ddfn;
if(son[u]) top[son[u]]=top[u],dfs2(son[u]);
int v,p;
for(p=fir[u];p;p=nxt[p]){
v=to[p];
if(v!=son[u]&&v!=fa[u])
top[v]=v,dfs2(v);
}
}
int LCA(int x,int y)
{
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
int tra[N];
void update(int x,int k)
{
if(!x)return;
while(x<=600000){
tra[x]=(1ll*tra[x]+1ll*mod+1ll*k)%mod;
x+=(x&-x);
}
}
int getsum(int x)
{
int ret=0;
while(x){
ret=(ret+tra[x])%mod;
x-=(x&-x);
}
return ret;
}
int val[N];
int main()
{
int n,m,Q,i,j,k,u,v,op;
n=gi();m=gi();Q=gi();
for(i=1;i<=m;i++){
u=gi();v=gi();
adde(u,v);
}
for(i=1;i<=n;i++)
if(!dfn[i])dfs(i,0);
memset(fir,0,sizeof(fir));cnt=0;
for(i=1;i<=pbccnt;i++)
for(j=0,k=pbc[i].size();j<k;j++)
adde(n+i,pbc[i][j]);
dfs1(1);top[1]=1;dfs2(1);
for(i=1;i<=Q;i++){
op=gi();
if(!op){
u=gi();v=gi();k=gi();
update(pos[fa[u]],k);update(pos[fa[v]],k);
int lca=LCA(u,v);
if(lca>n){
update(pos[lca],-k);(val[fa[lca]]+=k)%=mod;
lca=fa[lca],update(pos[fa[lca]],-k);
}
else{
update(pos[lca],-2*k%mod);
(val[lca]+=k)%=mod;
}
}
else{
u=gi();
int ans=val[u];
if(fa[u])u=fa[u],ans=(1ll*ans+1ll*getsum(pos[u]+siz[u]-1)+mod-getsum(pos[u]-1))%mod;
printf("%d\n",ans);
}
}
}
20200522A
題解:組合數——二項式定理——生成函數——等比數列求和
參考:Freopen大佬的博客
代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1000105
int n,m;
int pw[100],C[N],inv[N];
void exgcd(int a,int b,int &x,int &y)
{
if(!b){x=1,y=0;return;}
exgcd(b,a%b,y,x);
y-=(a/b)*x;
}
int cmod,cans;
void CRT(int ans,int mod)
{
int t1,t2;
exgcd(cmod,mod,t1,t2);
int A=cmod*mod;
cans=(1ll*cmod*t1%A*(ans-cans)+cans)%A;
cmod=A;
}
int solve(int p,int e,int mod)// calculate the answer mod p^e
{
int c=1,cnte=0,i,tmp;
inv[0]=inv[1]=1;
for(i=2;i<max(3,min(mod,m+2));i++)
exgcd(i,mod,inv[i],tmp);
for(i=1;i<=m+1;i++){
int x=n-i+1,y=i;
if(x)for(;x%p==0;x/=p,cnte++);
for(;y%p==0;y/=p,cnte--);
c=1ll*c*x%mod*inv[y%mod]%mod;
if(cnte>=e)C[i]=0;
else C[i]=1ll*c*pw[cnte]%mod;
}
int b=0,ret=0;
for(i=0;i<=m;i++){
b=1ll*(C[i+1]-b)*inv[2]%mod;
if(!(i&1)) ret=(ret+b)%mod;
}
return ret;
}
int solve2(int e,int mod)//answer mod 2^e
{
int c=1,cnte=0,i,tmp;
inv[0]=inv[1]=1;
for(i=2;i<=m+2+e;i++)
exgcd(i,mod,inv[i],tmp);
for(i=1;i<=m+2+e;i++){
int x=n-i+1,y=i;
if(x)for(;!(x&1);x>>=1)cnte++;
for(;!(y&1);y>>=1)cnte--;
c=1ll*c*x%mod*inv[y%mod]%mod;
if(cnte>=e)C[i]=0;
else C[i]=((1ll*c)<<cnte)%mod;
}
int b=0;
for(i=m+1+e;i>=m+2;i--)
b=(1ll*C[i]-2ll*b)%mod;
int ret=b;
for(i=m-1;i>=0;i--){
b=(1ll*C[i+2]-2ll*b)%mod;
if(!(i&1)) ret=(ret+b)%mod;
}
return ret;
}
int main()
{
int i,mod;
scanf("%d%d%d",&n,&m,&mod);
n+=2;if(n&1)n--;if(m&1)m--;
int cnte2=0;
for(;!(mod&1);mod>>=1,cnte2++);
//1000000000 1000000 536870912
cans=0;cmod=pw[0]=1;
for(i=3;i*i<=mod;i++){
if(mod%i==0){
int cnt=0;
while(mod%i==0){
mod/=i;cnt++;
pw[cnt]=pw[cnt-1]*i;
}
CRT(solve(i,cnt,pw[cnt]),pw[cnt]);
}
}
if(mod>1)CRT(solve(mod,1,mod),mod);
mod=1<<cnte2;
CRT(solve2(cnte2,mod),mod);
printf("%d\n",(cans%cmod+cmod)%cmod);
}