爲何8月份的考試拖到如今才發題解呢?ios
由於實際上這是咱們昨天才考的...只不過正好和某校8月份的模擬考試重題而已...算法
T1 題意簡述:jzoj5835數組
解題思路:很簡單的一道篩法題。優化
分析題目,發現只須要篩出[1,min(K,sqrt(R))]範圍內的質數便可。ui
#include<algorithm>//STL通用算法 #include<bitset>//STL位集容器 #include<cctype> #include<cmath> #include<complex> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #include<deque>//STL雙端隊列容器 #include<list>//STL線性列表容器 #include<map>//STL映射容器 #include<iostream> #include<queue>//STL隊列容器 #include<set>//STL集合容器 #include<stack>//STL堆棧容器 #include<utility>//STL通用模板類 #include<vector>//STL動態數組容器 #define INF 0x3f3f3f3f #define ll long long using namespace std; ll L,R,n,len,ans,sch[10000005]; ll cnt,pri[10000005],jdg[10000005]; void getpri() { jdg[1]=1; for(ll i=2;i<=n;i++) { if(!jdg[i]) pri[++cnt]=i; for(ll j=1;j<=cnt;j++) { if(pri[j]*i>n) break; jdg[i*pri[j]]=1; if(!(i%pri[j])) break; } } } int main() { freopen("prime.in","r",stdin); freopen("prime.out","w",stdout); scanf("%lld%lld%lld",&L,&R,&n); n=min((ll)sqrt(R),n),len=R-L+1; getpri(); for(ll i=1;i<=cnt;i++) { ll tmp=(L/pri[i]+(L%pri[i]!=0))*pri[i]-L+1; while(tmp<=len) sch[tmp]=1,tmp+=pri[i]; if(pri[i]>=L) sch[pri[i]-L+1]=0; } for(ll i=1;i<=len;i++) if(!sch[i]) ans^=L+i-1; printf("%lld\n",ans); return 0; }
T2 題意簡述:jzoj5836spa
解題思路:貪心+矩陣乘法。.net
首先考慮如何計算一個序列中的子序列個數。(子序列個數指互不重複的子序列個數。如下同理)code
題解中所給的式子是dp[num[i]]=∑(j=1,k)dp[j],其中dp[i]表示以i結尾的子序列個數。blog
其實有一種式子更易理解:dp[i]=dp[i-1]*2-dp[pos[num[i]]-1](pos[i]!=0)。隊列
其中dp[i]表示序列第i項的子序列個數,pos[i]表示數字i在序列中上一次出現的位置。
這個式子的意思是,在上一項的每一個子序列後面都填上一個num[i],可是還要減去重複的。
重複的子序列其實就是上次此數字出現時已經計入的子序列。固然,若還未出現過就沒必要減去了。
用這個方法能夠算出整個序列的子序列個數。
接下來考慮m個待填數字。
觀察式子,發現要使結果最大,只需使dp[pos[num]-1]最小便可。
易知,dp數組是單調遞增的。所以,只需保證pos[num]-1最小即可保證結果最大。
也就是說,每次取最先出現的那個元素做爲當前項便可。
直接遞推複雜度O(n+m),這樣的複雜度是沒法接受的。考慮優化。
衆所周知,遞推式能夠用矩陣乘法優化。最終複雜度O(n+k+k^3logm)。
爲何會有個(+k)?由於一開始的k項是沒法用矩陣乘法優化的。
pos在一開始的k項取值範圍爲[0,n],顯然咱們沒法建一個n*n的矩陣。
可是在經歷一個循環節後,pos的取值範圍就變成了[n+1,n+k],所以只需建一個(k+1)*(k+1)的矩陣便可。
#include<algorithm>//STL通用算法 #include<bitset>//STL位集容器 #include<cctype> #include<cmath> #include<complex> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #include<deque>//STL雙端隊列容器 #include<list>//STL線性列表容器 #include<map>//STL映射容器 #include<iostream> #include<queue>//STL隊列容器 #include<set>//STL集合容器 #include<stack>//STL堆棧容器 #include<utility>//STL通用模板類 #include<vector>//STL動態數組容器 #define INF 0x3f3f3f3f #define ll long long #define MOD 1000000007 using namespace std; ll n,m,k,ans,num[1000010],pos[110],que[110],dp[2000010]; struct uio{ ll pos,num; }srt[110]; struct oiu{ ll sqr[110][110]; oiu(){memset(sqr,0,sizeof(sqr));} friend oiu operator *(const oiu &x,const oiu &y) { oiu z; for(ll i=1;i<=k+1;i++) for(ll j=1;j<=k+1;j++) for(ll l=1;l<=k+1;l++) (z.sqr[i][j]+=x.sqr[i][l]*y.sqr[l][j]%MOD)%=MOD; return z; } }mat,bgn; bool cmp(uio x,uio y){return x.pos<y.pos;} void init(oiu &x) {for(ll i=1;i<=k+1;i++) x.sqr[i][i]=1;} oiu qpow(oiu x,ll y) { oiu z;init(z); while(y) {if(y&1) z=z*x;x=x*x;y/=2;} return z; } signed main() { freopen("sequence.in","r",stdin); freopen("sequence.out","w",stdout); scanf("%lld%lld%lld",&n,&m,&k); for(ll i=1;i<=n;i++) scanf("%lld",&num[i]); dp[0]=1; for(ll i=1;i<=n;i++) { if(pos[num[i]]) dp[i]=(dp[i-1]*2-dp[pos[num[i]]-1]+MOD)%MOD; else dp[i]=dp[i-1]*2%MOD; pos[num[i]]=i; } for(ll i=1;i<=k;i++) srt[i]={pos[i],i}; sort(srt+1,srt+1+k,cmp); for(ll i=1;i<=k;i++) que[i]=srt[i].num; for(ll i=n+1;i<=n+min(m,k);i++) { ll x=que[i-n]; if(pos[x]) dp[i]=(dp[i-1]*2-dp[pos[x]-1]+MOD)%MOD; else dp[i]=dp[i-1]*2%MOD; pos[x]=i; } m-=k;if(m<=0) {printf("%lld\n",dp[n+m+k]-1);return 0;} mat.sqr[1][1]=2,mat.sqr[k+1][1]=-1; for(ll i=1;i<=k;i++) mat.sqr[i][i+1]=1; for(ll i=1;i<=k+1;i++) bgn.sqr[1][i]=dp[n+k-i+1]; mat=qpow(mat,m); for(ll i=1;i<=k+1;i++) (ans+=bgn.sqr[1][i]*mat.sqr[i][1]%MOD+MOD)%=MOD; printf("%lld\n",(ans-1+MOD)%MOD); return 0; }
T3 題意簡述:jzoj5837
解題思路:不會。博主看了題解後仍是沒寫出來。
在這裏貼一個官方題解,有興趣的大佬可瞭解一下。