A.课后练习题
Solution:
注意到有,.
所以对于偶数k,满足
对于奇数k,满足
所以答案即为n-1/n+1的因子个数(除1外)
Code:
#include
#define rep(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
int main(){
long long n,k;scanf("%lld%lld",&n,&k);
n+=(k%2==1);n-=(k%2==0);
int ans=-1;
for(long long i=1;i*i<=n;i++){
if(n%i!=0)continue;
ans++;ans+=(i*i!=n);
}
printf("%lld\n",ans);
return 0;
}
B.拼图
Solution:
首先暴力搜出N从0到8的答案,
接着列出转移方程
(详细证明)
由于N过大,考虑矩阵乘法,笔者的设计如下(似乎冗余了一行啊。。。)
*(我是乘号)
=(我是等号)
PS:注意运算过程中由于需要取模,矩阵中的dp[n]可能为负数,输出是要注意加上模数。
Code:
#include
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define mo 1000000007
using namespace std;
int a[10][10];int b[10][10];int t[10][10];
template void chkmod(T &x,T y){x=(x+y)%mo;}
inline void scz(int q[][10],int w[][10]){
rep(i,1,9){
rep(j,1,9){
t[i][j]=0;
rep(k,1,9){
int nop=(1ll*q[i][k]*w[k][j])%mo;chkmod(t[i][j],nop);
}
}
}
rep(i,1,9){
rep(j,1,9)q[i][j]=t[i][j];
}
return;
}
int main(){
long long n;scanf("%lld",&n);
a[1][1]=a[1][2]=1;a[1][3]=2;a[1][4]=3;a[1][5]=9;a[1][6]=16;
a[1][7]=35;a[1][8]=65;a[1][9]=143;
if(n<9){printf("%d\n",a[1][n+1]);return 0;}
rep(i,1,8)b[i+1][i]=1;
b[2][9]=-1;b[4][9]=1;b[5][9]=-1;b[6][9]=5;b[8][9]=1;b[9][9]=1;
long long tmp=n-8;
while(tmp){
if(tmp&1)scz(a,b);
scz(b,b);
tmp>>=1;
}
printf("%d\n",(a[1][9]+mo)%mo);
return 0;
}
C.魔法
Solution:
我们很自然地考虑如果单独拎出一整个序列怎么回答询问,将该序列划分成若干段正好包含1-d的,
如分成和两组(多余的1个3忽略)。
设分出的段数为M,则显然,长度<=M的魔法都会被其包含。
其次,构造一个长度为M+1的不包含的魔法:选取每一段的最后一个数字,再选一个剩余部分中没有的数字即可。
接下来想办法处理多组询问:
首先可以用2-pointers处理出从i点开始划分,到哪里可正好分为一段,记作nxt[i]。
如果一个i的nxt[i]存在的话,我们可以从nxt[i]+1向i连一条边,这样我们可以得到一个森林,
那每一次询问l,r可以看成求l的祖先中,编号<=r的深度最小的祖先到l的距离+1。
询问和预处理参考倍增LCA即可。
Code:
#include
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define rep2(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
template void read(T &num){
char c=getchar();T f=1;num=0;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){num=(num<<3)+(num<<1)+(c^48);c=getchar();}
num*=f;
}
template void qwq(T x){
if(x>9)qwq(x/10);
putchar(x%10+'0');
}
template void write(T x){
if(x<0){x=-x;putchar('-');}
qwq(x);putchar('\n');
}
int co[500010];int nxt[500010];int t[1010];
struct wzy{
int nxt,vertice;
}edge[500010];
int head[500010];int len=0;
inline void add_edge(int x,int y){
edge[++len].nxt=head[x];edge[len].vertice=y;head[x]=len;return;
}
int f[500010][19];
inline void Pretreatment(int u,int fa){
f[u][0]=fa;
rep(i,1,18)f[u][i]=f[f[u][i-1]][i-1];
for(int i=head[u];i;i=edge[i].nxt){
int nop=edge[i].vertice;
Pretreatment(nop,u);
}
return;
}
int main(){
//freopen("magic2.in","r",stdin);
//freopen("magic.out","w",stdout);
int n,m,d;read(n);read(m);read(d);
rep(i,1,n)read(co[i]);
int r=1;t[co[1]]++;int cnt=1;
rep(i,1,n){
while(cnt!=d&&r!=n){r++;cnt+=(t[co[r]]==0);t[co[r]]++;}
if(r==n&&cnt!=d)break;
nxt[i]=r;cnt-=(t[co[i]]==1);t[co[i]]--;
}
rep(i,1,n+1){
if(!nxt[i]){Pretreatment(i,0);}
else{add_edge(nxt[i]+1,i);}
}
while(m--){
int l,r;read(l);read(r);
int ans=0;
rep2(i,18,0){
if(f[l][i]&&f[l][i]<=r+1){l=f[l][i];ans+=(1<