Atcoderui
求\(s\)中本質不一樣子序列的個數模\(10^9+7\)。兩個子序列不一樣當且僅當存在一種字符在二者中的出現次數不一樣。spa
\(|s|\le10^5\)設計
\(\prod_{i='a'}^{'z'}(\mbox{字符}i\mbox{出現的次數}+1)-1\)code
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; int gi(){ int x=0,w=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')w=0,ch=getchar(); while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } const int N=1e5+5; const int mod=1e9+7; int n,t[26],ans=1;char s[N]; int main(){ scanf("%d",&n);scanf("%s",s+1); for(int i=1;i<=n;++i)++t[s[i]-'a']; for(int i=0;i<26;++i)ans=1ll*ans*(t[i]+1)%mod; printf("%d\n",(ans+mod-1)%mod);return 0; }
有一個長爲\(n\)的序列,每一個位置有個顏色,能夠進行若干次操做,操做爲選擇兩個顏色相同的位置,將它們中間的位置所有變成這個顏色,求全部可能出現的顏色序列的方案數模\(10^9+7\)。ip
\(n,c_i\le2\times10^5\)get
\(f_i=f_{i-1}+[lst_i<i-1]f_{lst_i}\)string
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; int gi(){ int x=0,w=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')w=0,ch=getchar(); while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } const int N=2e5+5; const int mod=1e9+7; int n,f[N],lst[N]; int main(){ n=gi();f[0]=1; for(int i=1;i<=n;++i){ int a=gi(); f[i]=f[i-1]; if(lst[a]&&lst[a]<i-1)f[i]=(f[i]+f[lst[a]])%mod; lst[a]=i; } printf("%d\n",f[n]);return 0; }
構造一個\(0\)到\(2^n-1\)的排列,知足首位是\(A\)末位是\(B\),且相鄰兩個數在二進制下僅相差\(1\)位。it
\(n\le 17\)io
只須要構造首位是\(0\)末位是\(A \mbox{xor} B\)的排列再將全部數異或\(A\)就好了。ast
顯然,\(\mbox{popcount}(A\mbox{xor}B)\)爲偶數時必定無解,不然根據構造方法必定存在一組解。
考慮將模型轉化爲在\(n\)維超立方體上的遊走,須要遍歷這個超立方體\(2^n\)個頂點中的每個。一種可行的策略是,先遍歷\(n\)維超立方體中的某個\(n-1\)維超立方體,再一步走到另外一個\(n-1\)維超立方體上並遍歷之。
在本題中咱們要從\(0\)走到\(A\mbox{xor}B\),能夠選出一個二進制位\(p\)知足\(A\mbox{xor}B\)在第\(p\)位上值爲\(1\),遍歷二進制第\(p\)位爲\(0\)的全部點組成的\(n-1\)維超立方體後,再去遍歷二進制位第\(p\)位爲\(1\)的全部點組成的\(n-1\)維超立方體。兩個\(n-1\)維超立方體之間的鏈接點的選取是任意的,只須要知足起點終點二進制位不一樣的位數是奇數就好了。
#include<cstdio> #include<algorithm> using namespace std; int gi(){ int x=0,w=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')w=0,ch=getchar(); while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } #define pc(x) __builtin_popcount(x) int n,A,B,all; void dfs(int x,int y,int ban){ if(pc(ban^all)==1){printf("%d %d ",y,x^y);return;} for(int i=0;i<n;++i) if((~ban>>i&1)&&(x>>i&1)) for(int j=0;j<n;++j) if((~ban>>j&1)&&i!=j){ dfs(1<<j,y,ban|1<<i); dfs(x^(1<<i)^(1<<j),y^(1<<i)^(1<<j),ban|1<<i); return; } } int main(){ n=gi(),A=gi(),B=gi(),all=(1<<n)-1; if(pc(A^B)&1)puts("YES"),dfs(A^B,A,0); else puts("NO"); return 0; }
定義\(f(p,q)\)爲一個排列\(c\)知足\(c_{p_i}=q_i\),其中\(p,q\)均是\(1-n\)排列。已知\(a_1=p,a_2=q,a_n=f(a_{n-2},a_{n-1})(n>2)\),給出\(p,q\),求\(a_k\)。
\(n\le10^5,k\le10^9\)
\([f(p,q)]_{p_i}=q_i\to f(p,q)p=q\to f(p,q)=qp^{-1}\)
而後大力列出\(a_i\)的前若干項。
\[a_1=p\\a_2=q\\a_3=qp^{-1}\\a_4=qp^{-1}q^{-1}\\a_5=qp^{-1}q^{-1}pq^{-1}\\a_6=qp^{-1}q^{-1}ppq^{-1}\\a_7=qp^{-1}q^{-1}pqpq^{-1}\\a_8=qp^{-1}q^{-1}pqp^{-1}qpq^{-1}\]
而後令\(A=qp^{-1}q^{-1}p\),則可概括證實出\(a_n=Aa_{n-6}A^{-1}(n>6)\)。
因此就作完啦?
#include<cstdio> #include<algorithm> #include<vector> using namespace std; int gi(){ int x=0,w=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')w=0,ch=getchar(); while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } #define vi vector<int> int n,k;vi a[7]; vi readin(){ vi res(n); for(int i=0;i<n;++i)res[i]=gi()-1; return res; } void print(vi a){ for(int i=0;i<n;++i)printf("%d ",a[i]+1); puts(""); } vi inv(vi a){ vi res(n); for(int i=0;i<n;++i)res[a[i]]=i; return res; } vi mul(vi a,vi b){ vi res(n); for(int i=0;i<n;++i)res[i]=a[b[i]]; return res; } vi fastpow(vi a,int b){ vi res(n); for(int i=0;i<n;++i)res[i]=i; while(b){if(b&1)res=mul(res,a);a=mul(a,a);b>>=1;} return res; } int main(){ n=gi();k=gi(); vi p=readin(),q=readin(); a[1]=p;a[2]=q; for(int i=3;i<=6;++i)a[i]=mul(a[i-1],inv(a[i-2])); vi A=mul(mul(q,inv(p)),mul(inv(q),p)),B=fastpow(A,(k-1)/6); print(mul(mul(B,a[(k-1)%6+1]),inv(B)));return 0; }
二維平面上有\(n\)個珠寶,第\(i\)個珠寶的位置爲\((x_i,y_i)\),權值爲\(v_i\)。你能夠從中選取任意數量的珠寶,但須要知足以下\(m\)條限制:全部(橫/縱)座標(小/大)於等於\(a_i\)的珠寶中至多選\(b_i\)個。求能獲得的最大權值和。
\(n \le80,m\le 320,x_i,y_i,a_i\le100,v_i\le10^{15},b_i<n\)
首先這數據範圍看着就很費用流
先考慮一維怎麼作。
一個很妙的轉化是:限制橫座標\(\le a_i\)的珠寶裏至多選\(b_i\)個,等價於選擇的橫座標第\(b_i+1\)小的珠寶,其橫座標必須\(> a_i\)。
若是是限制橫座標\(\ge a_i\)的珠寶至多選\(b_i\)個,則能夠先枚舉選\(k\)個珠寶,而後限制就等價於選擇的第\(k-b_i\)個珠寶其橫座標必須\(<a_i\)。(以上只考慮\(b_i<k\)的限制,\(b_i\ge k\)的限制顯然無效)
這樣咱們就能夠獲得\(k\)個二元組\((l_j,r_j)\),分別表示第\(j\)個珠寶的橫座標的範圍限制。注意這\(k\)個二元組的\(l\)和\(r\)應知足單調不降。
這樣咱們就獲得了一個匹配的模型:二分圖一側有\(k\)個點,另外一側有\(n\)個點,知足範圍限制的點之間連邊,而後求一組最大權匹配便可。
至於二維的問題,能夠直接把圖拆成三份,即左側\(k\)個點表示橫座標的限制,中間\(2n\)個點內部連權值的邊表示珠寶,右側另\(k\)個點表示縱座標的限制。
#include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; #define ll long long ll gi(){ ll x=0,w=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')w=0,ch=getchar(); while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } int gc(){ char ch=getchar(); while(ch<'A'||ch>'Z')ch=getchar(); return ch; } const int N=405; struct edge{int to,nxt,w;ll cost;}E[N*N]; int n,m,x[N],y[N],t[N],a[N],b[N],L[N],R[N],D[N],U[N],head[N],cnt,S,T,vis[N],pe[N]; ll v[N],dis[N],ans;queue<int>Q; void link(int u,int v,ll w){ E[++cnt]=(edge){v,head[u],1,w};head[u]=cnt; E[++cnt]=(edge){u,head[v],0,-w};head[v]=cnt; } bool spfa(ll &res){ memset(dis,63,sizeof(dis)); dis[S]=0;Q.push(S); while(!Q.empty()){ int u=Q.front();Q.pop();vis[u]=0; for(int i=head[u],v;i;i=E[i].nxt) if(E[i].w&&dis[v=E[i].to]>dis[u]+E[i].cost){ dis[v]=dis[u]+E[i].cost;pe[v]=i; if(!vis[v])vis[v]=1,Q.push(v); } } if(dis[T]==dis[0])return false;res+=dis[T]; for(int i=T;i!=S;i=E[pe[i]^1].to)--E[pe[i]].w,++E[pe[i]^1].w; return true; } ll cal(int k){ for(int i=1;i<=k;++i)L[i]=D[i]=0,R[i]=U[i]=233; for(int i=1;i<=m;++i) if(b[i]<k){ if(t[i]=='L')L[b[i]+1]=a[i]+1; if(t[i]=='R')R[k-b[i]]=a[i]-1; if(t[i]=='D')D[b[i]+1]=a[i]+1; if(t[i]=='U')U[k-b[i]]=a[i]-1; } for(int i=2;i<=k;++i)L[i]=max(L[i],L[i-1]),D[i]=max(D[i],D[i-1]); for(int i=k-1;i;--i)R[i]=min(R[i],R[i+1]),U[i]=min(U[i],U[i+1]); memset(head,0,sizeof(head));cnt=1;S=n+k<<1|1;T=n+k+1<<1; for(int i=1;i<=n;++i)link(i,n+i,-v[i]-1000000000000000ll); for(int i=1;i<=k;++i){ link(S,n+n+i,0);link(n+n+k+i,T,0); for(int j=1;j<=n;++j){ if(L[i]<=x[j]&&x[j]<=R[i])link(n+n+i,j,0); if(D[i]<=y[j]&&y[j]<=U[i])link(n+j,n+n+k+i,0); } } ll res=0;while(spfa(res));return -res-1000000000000000ll*k; } int main(){ n=gi(); for(int i=1;i<=n;++i)x[i]=gi(),y[i]=gi(),v[i]=gi(); m=gi(); for(int i=1;i<=m;++i)t[i]=gc(),a[i]=gi(),b[i]=gi(); for(int i=1;i<=n;++i)ans=max(ans,cal(i)); printf("%lld\n",ans);return 0; }
有一張\(n\)點\(m\)邊無向圖和一個奇數\(mod\),邊有邊權,給出\(q\)組詢問,每次詢問是否存在一條從\(s\)走到\(t\)的長度對\(mod\)取模後等於\(r\)的路徑。路徑不要求是簡單路徑,便可以來回走。這裏路徑長度的定義並不是全部邊的長度之和,而是通過的第\(i\)條邊的長度乘上\(2^i\)之和。
\(n,m,q \le5\times10^4,3\le mod\le 10^6,2\nmid mod\)
把路徑反過來,問題轉化成了:
一我的初始在\(t\)點,有一個數\(x\)初值爲\(0\)。每當他走過一條長度爲\(c\)的邊,數\(x\)就會變成\(2x+c\)並對\(mod\)取模,問是否存在一條路徑使走到\(s\)點後數\(x\)剛好等於\(r\)。
這樣暴力的作法就是創建\(n\times mod\)個狀態而後連邊,詢問就是查詢狀態\((t,0)\)是否能夠到達狀態\((s,r)\)。
經過觀察能夠發現一些性質:
一、全部的邊(指狀態之間的連邊)都是雙向的。考慮一條邊\((a,b,c)\),經過這條邊能夠實現\((a,x)\to(b,2x+c)\to(a,4x+3c)\to(b,8x+7c)\to...\),而最終必定能夠回到狀態\((a,x)\)。證實略顯然在模意義下每一個\(x\)都有惟一對應的\(2x+c\)以及惟一對應的\(\frac{x-c}{2}\),因此走一個長度爲偶數的環就能回到原狀態了。
二、若是存在兩條邊\((u,v,a)\)和\((u,w,b)\),那麼就有\((u,x)\to(v,2x+a)\to(v,4x+3a)\)以及\((u,x)\to(w,2x+b)\to(u,4x+3b)\),也就是說狀態\((u,4x+3a)\)與狀態\((u,4x+3b)\)是等價的,即狀態\((u,x)\)與狀態\((u,x+3(a-b))\)是等價的。
由此,咱們能夠求出全部有公共點的邊的邊權之差的\(\gcd\)(因爲圖是連通的,因此這等價於任意兩條邊邊權之差的\(\gcd\)),設之爲\(g\),則對於全部點而言,狀態\((u,x)\)與狀態\((u,x+3g)\)均是等價的。那麼咱們就能夠令\(mod \gets \gcd(mod,3g)\)了。
觀察到此時每條邊的邊權\(\mod g\)都是相等的,不妨設爲\(z\)。能夠考慮經過一些奇技淫巧把\(z\)去掉:把全部邊權減去\(z\),同時把全部狀態的第二維擡高\(z\),即本來的\((u,x)\to(v,2x+c)\)變成\((u,x+z)\to(v,2(x+z-z)+(c-z)+z)=(v,2x+c)\)。這樣轉化後全部轉移均可以與轉化前一一對應,所以正確性不存在問題,而通過這樣的轉化後,咱們能夠發現每次轉移後非\(x\)項加上的常數都是\(g\)的倍數。所以,從一個狀態\((u,x)\)出發可以到達的全部狀態,必定均可以被表示成\((v,px+qg)\)的形式,其中\(p\)是\(2\)的非負整數次冪,\(q\)是任意非負整數,進一步的,由於\(mod|3g\),故\(q\in\{0,1,2\}\)。
而由於\((u,x)\to(v,2x+c)\to(u,4x+3c)=(u,4x)\),因此\(p\in\{1,2\}\)。因而,咱們即可以設計總共\(6n\)個狀態表示\((u,px+qg)\),其中\(u\in[1,n],p\in\{1,2\},q\in\{0,1,2\}\)。
這樣詢問時就須要詢問\((t,z)\)可否到達\((s,r+z)\)。至關於咱們須要找到一組\((p,q),p\in N^*,q\in\{0,1,2\}\),知足\((t,x)\)與\((s,(p\mod 2)x+qg)\)連通且\(pz+qg=r+z\)。因此能夠預處理出\([1,mod)\)中每一個數是否等於某個\(2\)的奇數/偶數次冪,而後對於每組詢問直接枚舉\((p,q)\)便可。
#include<cstdio> #include<algorithm> using namespace std; int gi(){ int x=0,w=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')w=0,ch=getchar(); while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } const int N=1e6+5; int n,m,q,mod,a[N],b[N],c[N],g,z,fa[N],chk[2][N]; int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} void link(int x,int y){fa[find(x)]=find(y);} int id(int u,int x,int y){return u*6+x*2+y;} int main(){ n=gi();m=gi();q=gi();mod=gi(); for(int i=1;i<=m;++i){ a[i]=gi(),b[i]=gi(),c[i]=gi(); g=__gcd(g,abs(c[i]-c[1])); } if(!g)g=mod;mod=__gcd(mod,3*g);z=c[1]%g; for(int i=0;i<n*6;++i)fa[i]=i; for(int i=1;i<=m;++i){ int u=a[i]-1,v=b[i]-1,w=(c[i]-z)/g%3; for(int x=0;x<3;++x){ link(id(u,x,0),id(v,(2*x+w)%3,1)); link(id(u,x,1),id(v,(2*x+w)%3,0)); link(id(v,x,0),id(u,(2*x+w)%3,1)); link(id(v,x,1),id(u,(2*x+w)%3,0)); } } for(int i=0,j=z;i<mod<<1;++i,j=(j<<1)%mod)chk[i&1][j]=1; while(q--){ int s=gi()-1,t=gi()-1,r=gi(),res=0; for(int x=0;x<3;++x) for(int y=0;y<2;++y) if(find(id(t,0,0))==find(id(s,x,y))) res|=chk[y][(r+z+(3-x)*g)%mod]; puts(res?"YES":"NO"); } return 0; }