NOIP2024集训Day60
非常好数论复习。
CF986F Oppa Funcan Style Remastered
给定
一共
首先,注意到我们可以把选的数的范围缩小到
那么现在问题就变成了判断能否用若干个数加出
但是还有一个问题就是同余最短路的复杂度是与最小的数相关的,如果
观察到如果当
- 当
的质因子数为 0,即 时,无解。 - 当
的质因子数为 1,即 时,判断 是否是 的质数。 - 当
的质因子数为 2 时,记这两个质因子分别为 ,那用裴蜀定理判断 是否存在非负整数解即可。
#include<bits/stdc++.h>
#define int __int128
using namespace std;
char buf[1000005],*p1,*p2;
#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
int read(){
int x=0,f=0,c=gc();
while(!isdigit(c))f|=(c=='-'),c=gc();
while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=gc();
return f?-x:x;
}
int exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1,y=0;
return a;
}
int gcd=exgcd(b,a%b,x,y);
int t=y;
y=x-(a/b)*y;
x=t;
return gcd;
}
int T,n,k,tot;
map<int,int>M;
vector<int>ps[55];
int dis[55][100005],sum[55],p[55];
bool vis[100005];
struct node{
int x,k;
bool operator<(const node &t)const{return k>t.k;}
};
priority_queue<node>q;
void D(int id){
for(int i=0;i<p[id];i++)dis[id][i]=1.5e18;
memset(vis,0,sizeof(vis));
dis[id][0]=0;
q.push(node({0,0}));
while(!q.empty()){
node tmp=q.top();
q.pop();
if(vis[tmp.x])continue;
vis[tmp.x]=1;
for(int i=1;i<sum[id];i++){
int v=(tmp.x+ps[id][i])%p[id],w=ps[id][i];
if(dis[id][v]>dis[id][tmp.x]+w){
dis[id][v]=dis[id][tmp.x]+w;
q.push(node({v,dis[id][v]}));
}
}
}
}
signed main()
{
T=read();
while(T--){
n=read(),k=read();
if(k==1){
puts("NO");
continue;
}
int id;
if(!M.count(k)){
id=M[k]=++tot;
for(int i=2;i*i<=k;i++){
if(k%i==0){
ps[tot].push_back(i);
while(k%i==0)k/=i;
}
}
if(k>1)ps[tot].push_back(k);
sum[tot]=ps[tot].size();
p[tot]=ps[tot][0];
if(sum[tot]>2){
D(id);
}
}
else id=M[k];
// cerr<<id<<' '<<sum[id]<<endl;
if(sum[id]==1)puts(n%p[id]==0?"YES":"NO");
else if(sum[id]==2){
int a=ps[id][0],b=ps[id][1],x,y;
exgcd(a,b,x,y);
x*=n;
y*=n;
// print(x),pc(' '),print(y),pc(10);
int l=(-x+b-1)/b,r=y/a;
// print(l),pc(' '),print(r),pc(10);
puts(l<=r?"YES":"NO");
}
else{
puts(n>=dis[id][n%p[id]]?"YES":"NO");
}
}
return 0;
}
CF571E Geometric Progressions
给定
第
询问最小的在
我们先特判掉存在
然后考虑将所有的
我们记
随后我们考虑依次将
高斯消元后如果发现方程组:
- 无解则表明原问题无解。
- 存在唯一解就判断它对应的数是否满足后续所有的数列
- 如果解出来发现
,就让 代替 继续与后面合并,注意特殊处理一下 时的情况。
#include<bits/stdc++.h>
#define int long long
using namespace std;
char buf[1000005],*p1,*p2;
#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
int read(){
int x=0,f=0,c=gc();
while(!isdigit(c))f|=(c=='-'),c=gc();
while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=gc();
return f?-x:x;
}
char puf[1000005];
int ptot;
#define pc(x) (ptot==1000000?(fwrite(puf,1,1000000,stdout),ptot=0,puf[ptot++]=x):puf[ptot++]=x)
void print(int x){
if(x<0){
pc('-');
print(-x);
return;
}
if(x>9)print(x/10);
pc(x%10+'0');
}
const int mod=1e9+7;
int exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1,y=0;
return a;
}
int gcd=exgcd(b,a%b,x,y);
int t=y;
y=x-(a/b)*y;
x=t;
return gcd;
}
int n,tot,p[2005],a[105],b[105],x[105][2005],y[105][2005];
int aa[2005][5];
struct node{
int x,y,mx,my;
};
int fpow(int a,int b){
int res=1;
while(b){
if(b&1)res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
node G(){
for(int i=1;i<=2;i++){
int k=0;
for(int j=i;j<=tot;j++){
if(aa[j][i]!=0){
k=j;
break;
}
}
if(!k)continue;
swap(aa[i][1],aa[k][1]);
swap(aa[i][2],aa[k][2]);
swap(aa[i][3],aa[k][3]);
for(int j=1;j<=tot;j++){
if(j!=i){
int gcd=__gcd(aa[i][i],aa[j][i]),x=aa[i][i]/gcd,y=aa[j][i]/gcd;
for(int l=1;l<=3;l++){
aa[j][l]*=x;
aa[j][l]-=aa[i][l]*y;
}
}
}
}
int X=-1e10,Y=-1e10;
for(int i=tot;i>=1;i--){
if(aa[i][1]==0&&aa[i][2]==0){
if(aa[i][3]){
puts("-1");
exit(0);
}
}
else if(aa[i][1]==0){
if(aa[i][3]%aa[i][2]){
puts("-1");
exit(0);
}
int yy=aa[i][3]/aa[i][2];
if(Y!=-1e10&&Y!=yy){
puts("-1");
exit(0);
}
Y=yy;
}
else if(aa[i][2]==0){
if(aa[i][3]%aa[i][1]){
puts("-1");
exit(0);
}
int xx=aa[i][3]/aa[i][1];
if(X!=-1e10&&X!=xx){
puts("-1");
exit(0);
}
X=xx;
}
else{
int xx=0,yy=0;
int gcd=exgcd(aa[i][1],aa[i][2],xx,yy);
if(aa[i][3]%gcd){
puts("-1");
exit(0);
}
xx*=aa[i][3]/gcd;
yy*=aa[i][3]/gcd;
int tx=aa[i][2]/gcd,ty=aa[i][1]/gcd;
tx=abs(tx),ty=ty;
xx=(xx%tx+tx)%tx;
yy=(yy%ty+ty)%ty;
return node({xx,yy,tx,ty});
}
}
return node({X,Y});
}
void check(){
int A=-1;
for(int i=1;i<=n;i++){
if(b[i]==1){
if(A!=-1&&A!=a[i]){
puts("-1");
exit(0);
}
}
}
if(A!=-1){
for(int i=1;i<=n;i++){
if(A%a[i]){
puts("-1");
exit(0);
}
int B=A/a[i];
while(B%b[i]==0)B/=b[i];
if(B!=1){
puts("-1");
exit(0);
}
}
}
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)a[i]=read(),b[i]=read();
check();
for(int i=1;i<=n;i++){
int x=a[i];
for(int j=2;j*j<=x;j++){
if(x%j==0){
p[++tot]=j;
while(x%j==0)x/=j;
}
}
if(x>1)p[++tot]=x;
x=b[i];
for(int j=2;j*j<=x;j++){
if(x%j==0){
p[++tot]=j;
while(x%j==0)x/=j;
}
}
if(x>1)p[++tot]=x;
}
sort(p+1,p+tot+1);
tot=unique(p+1,p+tot+1)-p-1;
for(int i=1;i<=n;i++){
int k=a[i];
for(int j=2;j*j<=k;j++){
if(k%j==0){
int l=lower_bound(p+1,p+tot+1,j)-p;
while(k%j==0)k/=j,x[i][l]++;
}
}
if(k>1)x[i][lower_bound(p+1,p+tot+1,k)-p]++;
k=b[i];
for(int j=2;j*j<=k;j++){
if(k%j==0){
int l=lower_bound(p+1,p+tot+1,j)-p;
while(k%j==0)k/=j,y[i][l]++;
}
}
if(k>1)y[i][lower_bound(p+1,p+tot+1,k)-p]++;
}
for(int i=1;i<n;i++){
for(int j=1;j<=tot;j++){
aa[j][1]=y[i][j];
aa[j][2]=-y[i+1][j];
aa[j][3]=x[i+1][j]-x[i][j];
}
node sss=G();
if(sss.mx==0){
for(int j=1;j<=tot;j++)x[i][j]+=sss.x*y[i][j];
bool f=1;
for(int k=i+1;k<=n;k++){
for(int j=1;j<=tot;j++){
if(y[k][j]){
if(x[i][j]<x[k][j]||(x[i][j]-x[k][j])%y[k][j]){
f=0;
j=tot+1;k=n+1;
break;
}
}
else if(x[i][j]!=x[k][j]){
f=0;
j=tot+1;k=n+1;
break;
}
}
}
if(f){
int ans=1;
for(int j=1;j<=tot;j++)ans=ans*fpow(p[j],x[i][j])%mod;
print(ans);
fwrite(puf,1,ptot,stdout);
return 0;
}
else{
puts("-1");
exit(0);
}
}
else{
if(sss.x==0&&x[i][1]<x[i+1][1])sss.x+=sss.mx;
for(int j=1;j<=tot;j++)x[i][j]+=sss.x*y[i][j];
for(int j=1;j<=tot;j++)y[i][j]*=sss.mx;
for(int j=1;j<=tot;j++)x[i+1][j]=x[i][j],y[i+1][j]=y[i][j];
}
}
int ans=1;
for(int j=1;j<=tot;j++)ans=ans*fpow(p[j],x[n][j])%mod;
print(ans);
fwrite(puf,1,ptot,stdout);
return 0;
}
随机数列
过了再补,等一手高手的题解。
AT_tenka1_2019_e Polynomial Divisors
给定
注意到对于一个质数
接下来我们对
- 若
,则 ,所以符合条件的只有 的质因子。 - 若
,那我们设 ,显然所有 是质因子是满足条件的。同时对于一些小于 的质数也有可能通过降幂改变系数让 是满足条件的。所以我们再暴力判断小于 的质数,并把合法的加入答案。
#include<bits/stdc++.h>
#define int long long
using namespace std;
char buf[1000005],*p1,*p2;
#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
int read(){
int x=0,f=0,c=gc();
while(!isdigit(c))f|=(c=='-'),c=gc();
while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=gc();
return f?-x:x;
}
char puf[1000005];
int ptot;
#define pc(x) (ptot==1000000?(fwrite(puf,1,1000000,stdout),ptot=0,puf[ptot++]=x):puf[ptot++]=x)
void print(int x){
if(x<0){
pc('-');
print(-x);
return;
}
if(x>9)print(x/10);
pc(x%10+'0');
}
int n,a[10005],b[10005];
vector<int>ans;
void ch(int x){
for(int i=0;i<=min(x,n);i++)b[i]=0;
for(int i=0;i<=n;i++)b[i%(x-1)]=(b[i%(x-1)]+a[i]%x+x)%x;
for(int i=0;i<=min(x,n);i++){
if(b[i])return;
}
ans.push_back(x);
}
int p[10005],tot;
bool f[100005];
void ss(){
for(int i=2;i<=10000;i++){
if(!f[i])p[++tot]=i;
for(int j=1;i*p[j]<=10000&&j<=tot;j++){
f[i*p[j]]=1;
if(i%p[j]==0)break;
}
}
}
signed main()
{
n=read();
for(int i=n;i>=0;i--)a[i]=read();
if(a[0]!=0){
int x=abs(a[0]);
for(int i=2;i*i<=x;i++){
if(x%i==0){
ch(i);
while(x%i==0)x/=i;
}
}
if(x>1)ch(x);
}
else{
ss();
int gcd=0;
for(int i=0;i<=n;i++)gcd=__gcd(gcd,a[i]);
gcd=abs(gcd);
for(int i=2;i*i<=gcd;i++){
if(gcd%i==0){
if(i>n)ans.push_back(i);
while(gcd%i==0)gcd/=i;
}
}
if(gcd>1&&gcd>n)ans.push_back(gcd);
for(int i=1;i<=tot&&p[i]<=n;i++){
ch(p[i]);
}
sort(ans.begin(),ans.end());
}
for(int x:ans)print(x),pc(10);
fwrite(puf,1,ptot,stdout);
return 0;
}
[WC2021] 斐波那契
众所周知,小葱同学擅长计算,尤其擅长计算组合数。但是对组合数有了充分研究的小葱同学对组合数失去了兴趣,而开始研究数列。
我们定义
现在给定
下午再写。
跳跳棋
跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。我们用跳跳棋来做一个简单的游戏:棋盘上有三颗棋子,分别在
跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过一颗棋子。
写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。
容易发现一个局面下最多只有 3 种不同的操作选择:将中间的向两边跳或者将某一边的棋子向中间跳。
常识告诉我们,这表明从一个局面出发能到达的所有局面构成一颗二叉树,而根代表的局面就是满足
然后按题意模拟去找初末局面的 LCA 即可。
#include<bits/stdc++.h>
#define int long long
using namespace std;
char buf[1000005],*p1,*p2;
#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
int read(){
int x=0,f=0,c=gc();
while(!isdigit(c))f|=(c=='-'),c=gc();
while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=gc();
return f?-x:x;
}
char puf[1000005];
int ptot;
#define pc(x) (ptot==1000000?(fwrite(puf,1,1000000,stdout),ptot=0,puf[ptot++]=x):puf[ptot++]=x)
void print(int x){
if(x<0){
pc('-');
print(-x);
return;
}
if(x>9)print(x/10);
pc(x%10+'0');
}
int a,b,c,x,y,z;
deque<string>q1,q2;
string get(int a,int b,int c){
return to_string(a)+"#"+to_string(b)+"#"+to_string(c);
}
string Get(int a,int b,int c,int l){
while(b-a!=c-b){
int l1=b-a,l2=c-b;
if(l1<l2){
int l3=(l2-1)%l1+1;
int tt=(l2-l3)/l1;
if(l<=tt){
l3=l2-l*l1;
b=c-l3;
a=b-l1;
break;
}
l-=tt;
b=c-l3;
a=b-l1;
}
else{
int l3=(l1-1)%l2+1;
int tt=(l1-l3)/l2;
if(l<=tt){
l3=l1-l*l2;
b=a+l3;
c=b+l2;
break;
}
l-=tt;
b=a+l3;
c=b+l2;
}
}
return get(a,b,c);
}
signed main()
{
a=read(),b=read(),c=read(),x=read(),y=read(),z=read();
if(a>b)swap(a,b);
if(b>c)swap(b,c);
if(a>b)swap(a,b);
if(b>c)swap(b,c);
if(x>y)swap(x,y);
if(y>z)swap(y,z);
if(x>y)swap(x,y);
if(y>z)swap(y,z);
int A=a,B=b,C=c,X=x,Y=y,Z=z;
q1.push_front(get(a,b,c));
int S=0,T=0;
while(b-a!=c-b){
int l1=b-a,l2=c-b;
if(b-a<c-b){
int l3=(l2-1)%l1+1;
S+=(l2-l3)/l1;
b=c-l3;
a=b-l1;
l2=l3;
}
else{
int l3=(l1-1)%l2+1;
S+=(l1-l3)/l2;
b=a+l3;
c=b+l2;
l1=l3;
}
q1.push_front(get(a,b,c));
}
q2.push_front(get(x,y,z));
while(y-x!=z-y){
int l1=y-x,l2=z-y;
if(y-x<z-y){
int l3=(l2-1)%l1+1;
T+=(l2-l3)/l1;
y=z-l3;
x=y-l1;
l2=l3;
}
else{
int l3=(l1-1)%l2+1;
T+=(l1-l3)/l2;
y=x+l3;
z=y+l2;
l1=l3;
}
q2.push_front(get(x,y,z));
}
if(q1[0]!=q2[0])puts("NO");
else{
int l=0,r=min(S,T),mid,res=S+T;
while(l<=r){
mid=l+r>>1;mid))l=mid+1,res=S-mid+T-mid;
else r=mid-1;
}
pc('Y'),pc('E'),pc('S'),pc(10);
print(res);
}
fwrite(puf,1,ptot,stdout);
return 0;
}
小凯的疑惑
给定正整数
简单题。
因为
#include<bits/stdc++.h>
#define int long long
using namespace std;
char buf[1000005],*p1,*p2;
#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
int read(){
int x=0,f=0,c=gc();
while(!isdigit(c))f|=(c=='-'),c=gc();
while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=gc();
return f?-x:x;
}
char puf[1000005];
int ptot;
#define pc(x) (ptot==1000000?(fwrite(puf,1,1000000,stdout),ptot=0,puf[ptot++]=x):puf[ptot++]=x)
void print(int x){
if(x<0){
pc('-');
print(-x);
return;
}
if(x>9)print(x/10);
pc(x%10+'0');
}
int a,b;
signed main()
{
a=read();b=read();
if(a==1||b==1)puts("0");
else print(a*b-a-b);
fwrite(puf,1,ptot,stdout);
return 0;
}
AGC063D Many CRT
给定系数
由于答案较大,请输出答案对 998244353 取模的结果。
设
因为
我们设
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现