2022.11.(12/14/15)题解
D1T1:预计紫
D1T2:预计蓝
D1T3:预计紫
D1T4:预计紫
D2T1:P2322 [HNOI2006]最短母串问题(紫)
D2T2:预计紫
D2T3:预计蓝
D2T4:预计蓝
D3T1:预计蓝
D3T2:预计紫
D3T3:预计紫
D3T4:2480 [SDOI2010]古代猪文(紫)
DAY1:
T1:
题目简述:
构造一棵
解:
暂无。
T2:
题目简述:
一个只包含的小写字母的字符串,给定
解:
可以看出来的是最后有
那么现在问题在于如何处理有多少块。
正常就想到,对于两个子串相等,说明每一位对应相等,将其放入一个并查集即可。
时间复杂度:
考虑优化。
可以知道的是,合并的次数是很少的,所以每次合并会有很多区间相等,如果两个区间相等,实际上就不用搜下去了,那么就想到用哈希判重,哈希值利用并查集编号映射。但是如果一个区间只有一个不同,会导致复杂度再次变高,所以想到分治,每次判断一个区间的子串是否需要合并,如果需要,再折半向下分,直到到边界,就合并这两个,合并利用启发式合并,修改哈希值用树状数组即可。
时间复杂度:
#include<iostream>
#include<cstdio>
#include<vector>
#define int long long
using namespace std;
const int N=1e6+5;
const int mod=1e9+7;
int n,m,f[N],t[N],p[N],vis[N];
vector<int>a[N];
int afind(int x)
{
if(x==t[x])return x;
return t[x]=afind(t[x]);
}
inline int lowbit(int x)
{
return x&(-x);
}
void update(int x,int k)
{
while(x<=n)
{
f[x]+=k;
f[x]%=mod;
x+=lowbit(x);
}
}
int search(int x)
{
int num=0;
while(x)
{
num+=f[x];
num%=mod;
x-=lowbit(x);
}
return num;
}
void divide(int l1,int r1,int l2,int r2)
{
if(((search(r1)-search(l1-1))*p[l2-l1]%mod+mod)%mod==(search(r2)-search(l2-1)%mod+mod)%mod)return;
if(l1==r1)
{
int t1=afind(l1),t2=afind(l2);
if(a[t1].size()>a[t2].size())swap(t1,t2);
int len=a[t1].size();
for(int i=0;i<len;i++)
{
update(a[t1][i],(t2-t1)*p[a[t1][i]-1]);
a[t2].push_back(a[t1][i]);
}
t[t1]=t[t2];
return;
}
int mid1=(l1+r1)>>1,mid2=(l2+r2)>>1;
divide(l1,mid1,l2,mid2);
divide(mid1+1,r1,mid2+1,r2);
}
signed main()
{
freopen("3-27.in","r",stdin);
freopen("dealing.out","w",stdout);
scanf("%lld%lld",&n,&m);
p[0]=1;
for(int i=1;i<=n;i++)p[i]=p[i-1]*N%mod,t[i]=i,update(i,t[i]*p[i-1]),a[i].push_back(i);
for(int i=1;i<=m;i++)
{
int len,x,y;
scanf("%lld%lld%lld",&len,&x,&y);
if(x>y)swap(x,y);
divide(x,len+x-1,y,y+len-1);
}
int ans=1;
for(int i=1;i<=n;i++)if(!vis[afind(i)])vis[afind(i)]=1,ans*=26,ans%=mod;
printf("%lld",ans);
return 0;
}
T3:
题目简述:
给定
解:
分组问题想到退火。
首先先按照线段从长到短排序,若相等按照左端点排序,那么预处理将前
这样的好处是可能很快骗到答案,且如果所有区间相等,按照左端点排序可以大大增加正确率。
求线段交答案只需要找到集合中最大的左端点与最小的右端点,这两个直接即是答案。
退火中用
正解貌似是动规。
#include<iostream>
#include<cstdio>
#include<queue>
#include<ctime>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<set>
#define Noir 'C'+'Z'+'B'
#define Diruixiao 0.996
#define WXD 1e-12
#define SuBtitle 300000
#define int long long
using namespace std;
const int N=1e5+5;
const double down=Diruixiao;
const double eps=WXD;
struct node
{
int name,data;
};
priority_queue<node>q1[N];
bool operator <(node fi,node se)
{
return fi.data<se.data;
}
struct node2
{
int name,data;
};
priority_queue<node2>q2[N];
bool operator <(node2 fi,node2 se)
{
return fi.data>se.data;
}
struct node3
{
int l,r;
}a[N];
int cmp(node3 fi,node3 se)
{
if(fi.r-fi.l==se.r-se.l)return fi.l<se.l;
return fi.r-fi.l>se.r-se.l;
}
int n,k,ans,siz[N],vis[N],sum;
int lim;
set<int>s;
void getto(int x,int y)
{
//cout<<siz[vis[x]]<<" sadf"<<siz[y]<<endl;
int t=vis[x];
while(vis[q1[t].top().name]!=t)q1[t].pop();
while(vis[q2[t].top().name]!=t)q2[t].pop();
int num1=0;
if(q2[t].top().data>q1[t].top().data)num1=q2[t].top().data-q1[t].top().data;
while(!q1[y].empty()&&vis[q1[y].top().name]!=y)q1[y].pop();
while(!q2[y].empty()&&vis[q2[y].top().name]!=y)q2[y].pop();
int num3=0;
if(!q1[y].empty()&&q2[y].top().data>q1[y].top().data)num3=q2[y].top().data-q1[y].top().data;
vis[x]=y;
while(!q1[t].empty()&&vis[q1[t].top().name]!=t)q1[t].pop();
while(!q2[t].empty()&&vis[q2[t].top().name]!=t)q2[t].pop();
int num2=0;
if(!q1[t].empty()&&q2[t].top().data>q1[t].top().data)num2=q2[t].top().data-q1[t].top().data;
sum+=(num2-num1);
q1[y].push({x,a[x].l}),q2[y].push({x,a[x].r});
while(vis[q1[y].top().name]!=y)q1[y].pop();
while(vis[q2[y].top().name]!=y)q2[y].pop();
int num4=0;
if(q2[y].top().data>q1[y].top().data)num4=q2[y].top().data-q1[y].top().data;
sum+=(num4-num3);
siz[t]--,siz[y]++;
if(siz[t]==1)
{
while(vis[q1[t].top().name]!=t)q1[t].pop();
while(vis[q2[t].top().name]!=t)q2[t].pop();
s.erase(q1[t].top().name);
}
s.insert(x);
}
void sa()
{
double T=SuBtitle;
while(T>eps)
{
if(clock()*1.0/CLOCKS_PER_SEC>1.9)return;
int y=rand()%n+1,l=*(s.begin()),r=*(--s.end()),num=rand()%(r-l+1)+l;
int x=*s.lower_bound(num);
if(x==y)y=rand()%n+1;
if(lim)lim--,x=k;
int t=vis[x];
getto(x,vis[y]);
if(ans<sum)ans=sum;
else if(exp((double)(ans-sum)*1.0/T)*RAND_MAX>rand())getto(x,t);
T*=down;
}
}
signed main()
{
freopen("3-38.in","r",stdin);
//freopen("lunatic.out","w",stdout);
srand(Noir);
scanf("%lld%lld",&n,&k);
for(int i=1;i<=n;i++)scanf("%lld%lld",&a[i].l,&a[i].r);
sort(a+1,a+1+n,cmp);
for(int i=1;i<k;i++)q1[i].push({i,a[i].l}),q2[i].push({i,a[i].r}),ans+=a[i].r-a[i].l,siz[i]=1,vis[i]=i;
for(int i=k;i<=n;i++)q1[k].push({i,a[i].l}),q2[k].push({i,a[i].r}),vis[i]=k,s.insert(i);
siz[k]=n-k+1;
lim=(n-k+1)/2;
if(q2[k].top().data>q1[k].top().data)ans+=q2[k].top().data-q1[k].top().data;
if(n==k)
{
printf("%lld",ans);
return 0;
}
sum=ans;
while(clock()*1.0/CLOCKS_PER_SEC<1.9)sa();
printf("%lld",ans);
return 0;
}
/*
10 4
9 10
3 4
1 3
2 8
2 6
1 7
1 6
6 8
6 8
6 8
*/
T4:
题目简述:
给定一个初始为
解:
不会。
DAY2:
T1:
题意简述:
给定
解:
状压字符串,在
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
#include<cstdlib>
using namespace std;
const int N=13;
const int M=51;
int n,t[N*M][26],cnt,state[N*M],fail[N*M],vis[N*M][1<<(N-1)],ans[N*M];
char st[M];
void insert(int id)
{
int len=strlen(st+1),x=0;
for(int i=1;i<=len;i++)
{
if(!t[x][st[i]-'A'])t[x][st[i]-'A']=++cnt;
x=t[x][st[i]-'A'];
}
state[x]|=(1<<id);
}
queue<int>q;
void getfail()
{
for(int i=0;i<26;i++)if(t[0][i])q.push(t[0][i]);
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=0;i<26;i++)
{
if(t[x][i])
{
fail[t[x][i]]=t[fail[x]][i];
state[t[x][i]]|=state[fail[t[x][i]]];
q.push(t[x][i]);
}
else t[x][i]=t[fail[x]][i];
}
}
}
struct node
{
int name,data,pre;
char ch;
}s[N*M*(1<<(N-1))];
void bfs()
{
int r=0;
s[++r]={0,0,0,0};
vis[0][0]=1;
int cnt=1;
while(cnt<=r)
{
int x=s[cnt].name,dat=s[cnt].data;
//cout<<dat<<" "<<(1<<n)-1<<endl;
if(dat==(1<<n)-1)
{
int p=cnt,rt=0;
while(p)
{
ans[++rt]=(int)s[p].ch;
p=s[p].pre;
}
for(int i=rt-1;i>0;i--)putchar(ans[i]);
exit(0);
}
for(int i=0;i<26;i++)
{
int xx=t[x][i],data=dat|state[t[x][i]];
if(vis[xx][data])continue;
vis[xx][data]=1;
s[++r]={xx,data,cnt,(char)(i+'A')};
}
cnt++;
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%s",st+1),insert(i-1);
getfail();
bfs();
return 0;
}
T2:
题意简述:
给定长度为
解:
分块。
预处理出来每个分块的所有
查询就正常分块即可。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=1e5+5;
const int M=320;
int n,m,a[N],ans[M][N],vis[N],p[N],k;
int main()
{
freopen("flower0.in","r",stdin);
freopen("flower.out","w",stdout);
scanf("%d%d",&n,&m);
k=sqrt(n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),p[i]=(i-1)/k+1;
for(int i=1;i*(k-1)+1<=n;i++)
{
for(int j=(i-1)*k+1;j<=min(i*k,n);j++)vis[a[j]]=a[j];
for(int j=1;j<=N-5;j++)vis[j]=max(vis[j],vis[j-1]);
for(int j=1;j<=N-5;j++)for(int t=0;t<=N-5;t+=j)ans[i][j]=max(ans[i][j],vis[min(N-5,t+j-1)]-t);
for(int j=1;j<=N-5;j++)vis[j]=0;
}
while(m--)
{
int l,r,t;
scanf("%d%d%d",&l,&r,&t);
int res=0;
for(int i=l;i<=min(r,p[l]*k);i++)res=max(res,a[i]%t);
for(int i=p[l]+1;i<p[r];i++)res=max(res,ans[i][t]);
for(int i=max(l,(p[r]-1)*k+1);i<=r;i++)res=max(res,a[i]%t);
printf("%d\n",res);
}
return 0;
}
T3:
题意简述:
给定
解:
正常人会想按照
所以应该按照
想出用 dp,设
否则:
由于其实舍去了一位,舍去了下一个端点的编号,利用背包思想,可以倒序枚举处理后效性。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int mod=1000000007;
const int N=6006;
int n,ans;
int f[N][2];
struct node
{
int x,y;
}a[N];
int cmp(node fi,node se)
{
return fi.x<se.x;
}
int read()
{
char ch=getchar();
int f=1,sum=0;
while(ch>'9'||ch<'0')
{
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
sum=(sum<<1)+(sum<<3)+(ch^48);
ch=getchar();
}
return sum*f;
}
signed main()
{
freopen("refract.in","r",stdin);
freopen("refract.out","w",stdout);
n=read();
for(int i=1;i<=n;i++)a[i].x=read(),a[i].y=read();
sort(a+1,a+1+n,cmp);
int ans=0;
for(int i=1;i<=n;i++)
{
f[i][0]=f[i][1]=1;
// cout<<"fuck you";
for(int j=i-1;j>0;j--)
{
if(a[i].y<a[j].y)f[j][0]+=f[i][1],f[j][0]%=mod;
else f[i][1]+=f[j][0],f[i][1]%=mod;
}
}
for(int i=1;i<=n;i++)
{
ans+=f[i][0];
ans%=mod;
ans+=f[i][1];
ans%=mod;
ans--;
ans=(ans%mod+mod)%mod;
}
printf("%d",ans);
return 0;
}
T4:
题意简述:
给定一个初始全为
解:
可以想到,我们先把所有目标该染成黑色的染成黑色,再处理那些不应该是黑色的。
想到二分图,可是发现不行,所以就想到能不能贪心去求。
对于每一个边连通分量出发,能走到最远的与自己颜色相同的通分量即是要染色的次数。
最后取最小值,至于正确性,我们可以把走路看成对这一块与从之前走过来的整条路径染色,那么改变了
#include<iostream>
#include<cstdio>
#include<deque>
#define int long long
using namespace std;
const int N=55;
int n,m,a[N][N],col[N][N],color,f[4][2]={{1,0},{0,1},{-1,0},{0,-1}},cnt,ans=1e9,dis[N*N],vis[N][N];
void dfs(int x,int y,int c)
{
col[x][y]=c;
for(int i=0;i<4;i++)
{
int xx=x+f[i][0],yy=y+f[i][1];
if(xx<1||xx>n||yy<1||yy>m||col[xx][yy]||a[x][y]!=a[xx][yy])continue;
dfs(xx,yy,c);
}
}
struct node
{
int x,y,data;
};
deque<node>q;
void bfs(int xb,int yb)
{
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)vis[i][j]=0;
for(int i=1;i<=color;i++)dis[i]=1e9;
q.push_back({xb,yb,1});
dis[col[xb][yb]]=1;
while(!q.empty())
{
int x=q.front().x,y=q.front().y,dat=q.front().data;
vis[x][y]=1;
q.pop_front();
for(int i=0;i<4;i++)
{
int xx=x+f[i][0],yy=y+f[i][1];
if(xx<1||yy<1||xx>n||yy>m)continue;
if(col[x][y]==col[xx][yy]&&!vis[xx][yy])q.push_front({xx,yy,dat});
if(col[x][y]!=col[xx][yy]&&dat+(a[xx][yy]^a[x][y])<dis[col[xx][yy]])
{
dis[col[xx][yy]]=dat+(a[xx][yy]^a[x][y]);
if(a[xx][yy]==1)q.push_front({xx,yy,dis[col[xx][yy]]});
else q.push_back({xx,yy,dis[col[xx][yy]]});
}
}
}
int res=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)if(a[i][j])res=max(res,dis[col[i][j]]);
}
ans=min(ans,res);
}
signed main()
{
freopen("paint.in","r",stdin);
freopen("paint.out","w",stdout);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%1lld",&a[i][j]);
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(!col[i][j])dfs(i,j,++color);
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)bfs(i,j);
printf("%lld",ans);
return 0;
}
DAY3:
T1:
题意简述:
给定一串初始为
解:
很容易想到广搜,至于怎么优化,先无效性剪枝一波,再无效性剪枝一波,最后再无效性剪枝一波,然后就卡过去了……
正解用
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int N=1e5+5;
int n,k,m,s,a[N],ans[N],vis[N],num;
struct node
{
int name,data;
};
queue<node>q;
int read()
{
char ch=getchar();
int sum=0;
while(ch>'9'||ch<'0')ch=getchar();
while(ch>='0'&&ch<='9')sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
return sum;
}
void write(int x)
{
if(x/10)write(x/10);
putchar((x%10)^48);
}
void bfs()
{
for(int i=1;i<=n;i++)ans[i]=2e9;
q.push({s,0});
ans[s]=0;
vis[s]=1;
int sum=0;
while(!q.empty())
{
int x=q.front().name,dat=q.front().data;
ans[x]=dat;
sum++;
if(sum==num)break;
q.pop();
if(!(x-k-2>0&&ans[x-2]<1e9))
{
for(int i=k%2+1,num=k/2-1;i<=k;i+=2,num--)
{
if(x-i-num<1)break;
if(x+num>n)
{
i+=(num-(n-x))*2;
num=n-x;
}
if(!a[x-i]&&!vis[x-i])
{
vis[x-i]=1;
q.push({x-i,ans[x]+1});
}
}
}
if(!(x+k+2<=n&&ans[x+2]<1e9))
{
for(int i=k%2+1,num=k/2-1;i<=k;i+=2,num--)
{
if(x+i+num>n)break;
if(x-num<1)
{
i+=(num-(x-1))*2;
num=x-1;
}
if(!a[x+i]&&!vis[x+i])
{
vis[x+i]=1;
q.push({x+i,ans[x]+1});
}
}
}
}
for(int i=1;i<=n;i++)
{
if(ans[i]>1e9)putchar('-'),putchar('1');
else write(ans[i]);
if(i!=n)putchar(' ');
}
}
int main()
{
freopen("reverse.in","r",stdin);
freopen("reverse.out","w",stdout);
n=read(),k=read(),m=read(),s=read();
for(int i=1;i<=m;i++)
{
int x;
x=read();
a[x]=1;
}
for(int i=1;i<=n;i++)num+=(a[i]^1);
bfs();
return 0;
}
T2:
题目简述:
给定正视图与左视图,求方块拜放方案数,正视图与左视图用数字代表高度。
首先可以将正视图与左视图的高度排个序,是不会影响结果的,因为实际上我们需要的是对于每一行每一列的最大值都对应的正视图与左视图的一个数,所以改变数位置在每种情况只需要交换行或列可以使其仍然满足条件。
排了序后,对于横竖交错的格子如果对应的两个数相同,那么这一类格子我们可以用组合数求加容斥求。
首先用组合数求出所有的情况,再先减去至少一行不符合条件,加上至少两行符合条件的情况,这些步骤就是容斥,求遍容斥即可。
#include<iostream>
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
const int N=1e5+5;
const int mod=1000000007;
int n,a[N],b[N],vis1[N],vis2[N],t[N],power[2*N],p[2*N],q[2*N];
struct node
{
int name,data;
}num[2*N];
int cmp(node fi,node se)
{
return fi.data<se.data;
}
int read()
{
char ch=getchar();
int sum=0;
while(ch>'9'||ch<'0')ch=getchar();
while(ch>='0'&&ch<='9')sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
return sum;
}
void write(int x)
{
if(x/10)write(x/10);
putchar((x%10)^48);
}
int quick_pow(int x,int y)
{
int sum=1,num=x;
while(y)
{
if(y&1)sum*=num,sum%=mod;
num*=num;
num%=mod;
y>>=1;
}
return sum;
}
int solve(int x,int y,int lenx,int leny,int num)
{
int tot=0;
for(int i=0;i<=lenx;i++)
{
int res=quick_pow(((quick_pow(num+1,(x+lenx)-i)-quick_pow(num,(x+lenx)-i))+mod)%mod,leny);
res*=quick_pow(num+1,(lenx-i)*y)*quick_pow(num,i*(y+leny))%mod;
res%=mod;
res*=power[lenx]*p[i]%mod*p[lenx-i]%mod;
res%=mod;
if(i&1)tot-=res;
else tot+=res;
tot=(tot%mod+mod)%mod;
}
return tot;
}
signed main()
{
//freopen("silhouette.in","r",stdin);
//freopen("silhouette.out","w",stdout);
n=read();
for(int i=1;i<=n;i++)a[i]=read(),num[i]={i,a[i]};
for(int i=1;i<=n;i++)b[i]=read(),num[i+n]={i+n,b[i]};
sort(num+1,num+1+2*n,cmp);
int cnt=0;
num[0].data=-1;
for(int i=1;i<=2*n;i++)
{
if(num[i].data!=num[i-1].data)q[++cnt]=num[i].data;
if(num[i].name<=n)a[num[i].name]=cnt;
else b[num[i].name-n]=cnt;
}
sort(a+1,a+1+n);
reverse(a+1,a+1+n);
sort(b+1,b+1+n);
reverse(b+1,b+1+n);
int rx=0,ry=0,ans=1;
power[0]=p[0]=1;
for(int i=1;i<=2*n;i++)power[i]=power[i-1]*i,p[i]=quick_pow(power[i],mod-2);
for(int i=cnt;i>=1;i--)
{
int lx=rx,ly=ry;
while(a[rx+1]==i)rx++;
while(b[ry+1]==i)ry++;
ans*=solve(lx,ly,rx-lx,ry-ly,q[i]);
ans%=mod;
}
write(ans);
return 0;
}
T3:
题目简述:
有
解:
由于当距离为一个值时初始的区间长度集合一定是固定的,所以可以先预处理出来这个集合,然后分为偶数区间与奇数区间处理,中间设
(不要怀疑,就是赶出来的题解)
#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
const int N=1050;
int n,mod,p[N],vis[N],pos[N],cnt[N],even[N],f[N][N],dp[N][N],g[N][N];
int quick_pow(int x,int y)
{
int sum=1,num=x;
while(y)
{
if(y&1)sum*=num,sum%=mod;
num*=num;
num%=mod;
y>>=1;
}
return sum;
}
signed main()
{
// freopen("seat.in","r",stdin);
//freopen("seat.out","w",stdout);
scanf("%lld%lld",&n,&mod);
for(int i=0;i<=n;i++)p[i]=quick_pow(i,mod-2);
for(int i=1;i<=n;i++)
{
int lc=1,rc=0,l=1;
for(int j=1;j<=n;j++)
{
if(vis[j])l=j+1;
if(j-l+1>rc-lc+1)rc=j,lc=l;
}
int mid=(lc+rc)>>1,len=(rc-lc+2)>>1;
pos[i]=mid;
cnt[len]++;
vis[mid]=1;
if((rc-lc+1)%2==0)even[len]++;
}
int lim=n;
for(int i=1;i<=n;i++)
{
if(!cnt[i])continue;
//cout<<i<<" "<<cnt[i]<<endl;
int l=lim-cnt[i]+1,r=lim,t=l+even[i]-1;
lim=l-1;
if(i==1)
{
for(int j=l;j<=r;j++)for(int k=l;k<=r;k++)dp[j][pos[k]]=p[cnt[i]];
continue;
}
for(int j=0;j<=cnt[i];j++)for(int k=0;k<=even[i];k++)f[j][k]=0;
f[0][even[i]]=1;
for(int j=1;j<=cnt[i];j++)
{
int sumodd=0,sumeven=0;
for(int k=0;k<=even[i];k++)
{
if(!f[j-1][k])continue;
if(k)
{
int num=f[j-1][k]*k%mod*2%mod*p[cnt[i]-j+1+k]%mod;
f[j][k-1]+=num;
f[j][k-1]%=mod;
sumeven+=num*p[even[i]*2];
sumeven%=mod;
}
if(cnt[i]-j+1>k)
{
int num=f[j-1][k]*((cnt[i]-j+1-k)%mod+mod)%mod*p[cnt[i]-j+1+k]%mod;
f[j][k]+=num;
f[j][k]%=mod;
sumodd+=num*p[cnt[i]-even[i]]%mod;
sumodd%=mod;
}
}
for(int k=l;k<=t;k++)
{
dp[l+j-1][pos[k]]+=sumeven,dp[l+j-1][pos[k]]%=mod;
dp[l+j-1][pos[k]+1]+=sumeven,dp[l+j-1][pos[k]+1]%=mod;
}
for(int k=t+1;k<=r;k++)dp[l+j-1][pos[k]]+=sumodd,dp[l+j-1][pos[k]]%=mod;
}
for(int j=l;j<=t;j++)
{
int lc=pos[j]-i+1,rc=pos[j]+i;
for(int k=lc;k<=rc;k++)
{
if(k==pos[j])continue;
int q=rc-(k-lc);
if(k>pos[j])q=lc+(rc-k);
for(int s=r+1;s<=n;s++)
{
g[s][k]+=dp[s][k]*p[2];
g[s][k]%=mod;
g[s][q]+=dp[s][k]*p[2];
g[s][q]%=mod;
}
}
for(int k=lc;k<=rc;k++)for(int s=r+1;s<=n;s++)dp[s][k]=g[s][k],g[s][k]=0;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)printf("%lld ",dp[i][j]);
printf("\n");
}
return 0;
}
T4:
题目描述:
给定
解:
分解
#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
const int mod=999911659;
int n,g,a[4]={2,3,4679,35617},power[35618][4],t[4];
int quick_pow(int x,int y,int p)
{
int sum=1,num=x;
while(y)
{
if(y&1)sum*=num,sum%=p;
num*=num;
num%=p;
y>>=1;
}
return sum;
}
int C(int x,int y,int p,int id)
{
if(x<y)return 0;
return power[x][id]*quick_pow(power[y][id],p-2,p)%p*quick_pow(power[x-y][id],p-2,p)%p;
}
int Lucas(int x,int y,int p,int id)
{
if(x<y)return 0;
if(x<p)return C(x,y,p,id)%p;
return C(x%p,y%p,p,id)*Lucas(x/p,y/p,p,id)%p;
}
int CRT()
{
int sum=0;
for(int i=0;i<4;i++)sum+=t[i]*(mod-1)/a[i]%(mod-1)*quick_pow((mod-1)/a[i],a[i]-2,a[i])%(mod-1),sum%=(mod-1);
return sum;
}
signed main()
{
freopen("ancient.in","r",stdin);
freopen("ancient.out","w",stdout);
scanf("%lld%lld",&n,&g);
if(g%mod==0)
{
printf("0");
exit(0);
}
power[0][0]=power[0][1]=power[0][2]=power[0][3]=1;
for(int i=1;i<=35617;i++)for(int j=0;j<4;j++)power[i][j]=power[i-1][j]*i%a[j];
for(int i=1;i*i<=n;i++)
{
if(n%i==0)
{
for(int j=0;j<4;j++)t[j]+=Lucas(n,i,a[j],j),t[j]%=a[j];
if(i*i!=n)for(int j=0;j<4;j++)t[j]+=Lucas(n,n/i,a[j],j),t[j]%=a[j];
}
}
int ans=quick_pow(g,CRT(),mod);
printf("%lld",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话