T1——gcd(3915)
Description:
给你两个数
A
A
,,求
gcd(An+Bn,A−B)mod(109+7)
gcd
(
A
n
+
B
n
,
A
−
B
)
m
o
d
(
10
9
+
7
)
.特殊地,
gcd(0,x)=x
gcd
(
0
,
x
)
=
x
.
A,B,n≤1018,B≤A
A
,
B
,
n
≤
10
18
,
B
≤
A
Solution:
- 关于此题,不知道是被题面误导要因式分解,还是被NOIP2017D1T1所敏感地去打表…
- 反正一开始就没想到正解上,接近自闭…
- 但当开始走投无路的去肉模拟这个玩意的时候 gcd(An+Bn,A−B) gcd ( A n + B n , A − B ) ,发现推了一次得到 gcd(A−B,(An+Bn)mod(A−B)) gcd ( A − B , ( A n + B n ) m o d ( A − B ) ) ,就感觉这个好像就是将 gcd g c d 肉拆一次,再次 gcd g c d …
- 真的无语…有点脑筋急转弯的味道…
Code:
#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;
template<class T>inline void Rd(T &x){
x=0;char c;
while((c=getchar())<48);
do x=(x<<1)+(x<<3)+(c^48);
while((c=getchar())>47);
}
#define mod 1000000007
ll A,B,K;
ll gcd(ll x,ll y){return !y?x:gcd(y,x%y);}
struct p50{
ll Pow(ll a,ll b){
ll x=1;
while(b){
if(b&1)x=x*a%mod;
b>>=1,a=a*a%mod;
}
return x;
}
void solve(){
ll X=A-B;
ll Y=Pow(A,K)+Pow(B,K);
if(!X)printf("%lld\n",Y%mod);
else {
ll d=gcd(X,Y)%mod;
printf("%lld\n",d);
}
}
}p1;
struct p100{
ll Mul(ll x,ll y,ll P){
ll res=0;
while(y){
if(y&1)res=(res+x)%P;
y>>=1;
x=(x<<1)%P;
}
return res;
}
ll Pow(ll a,ll b,ll P){
ll x=1;
while(b){
if(b&1)x=Mul(x,a,P);
a=Mul(a,a,P);
b>>=1;
}
return x;
}
void solve(){
ll X=A-B;
if(!X)printf("%lld\n",(Pow(A,K,mod)+Pow(B,K,mod))%mod);
else {
ll Y=(Pow(A,K,X)+Pow(B,K,X))%X;
printf("%lld\n",gcd(X,Y)%mod);
}
}
}p2;
int main(){
// freopen("gcd.in","r",stdin);
// freopen("gcd.out","w",stdout);
Rd(A),Rd(B),Rd(K);
if(A<=9 && B<=9 && K<=9)p1.solve();
else p2.solve();
return 0;
}
T2——triangle(3916)
Description:
有一个长度为
n
n
的序列{},表示木棒的长度.我们将用这些木棒拼出周长最大的三角形.
那么有
q
q
个操作.
- ,
pos
p
o
s
,
val
v
a
l
.将
Apos=val
A
p
o
s
=
v
a
l
-
op=2
o
p
=
2
,l,r.对区间
[l,r]
[
l
,
r
]
进行询问最大的三角形周长.
n,q≤105,Ai≤109 n , q ≤ 10 5 , A i ≤ 10 9 Solution:
- 对于三角形的周长问题,最近也是频繁遇到.
- 而此题是带单点修改的.那么显然是用线段树解决.
- 那么线段树的关键还是合并问题.
- 我们发现,在树上直接存答案是不太现实的.
- 那么我们只能是存该区间的一些木棒.
- 而我们要的是最大的周长,那么关键字一定是 > > .
- 这里,我觉得自己的做法还是偏无脑的做法.
- 因为分析修改的,对于每个区间影响的 Ai A i ,其实是只有 logq log q 个.
- 那么我们就在树上存上每个区间的前 logq log q 大 Ai A i 即可.
- 最后询问暴力来取 max m a x .
Code:
#include<bits/stdc++.h> using namespace std; #pragma GCC optimize("Ofast") #define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i) #define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;++i) #define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i) #define db double #define ll long long #define INF 0x3f3f3f3f #define inf 0x3f3f3f3f3f3f3f #define MINF 0xc0c0c0c0 #define Sz(l) sizeof(l) #define mcl(l,b) memset(l,b,Sz(l)) #define mcp(l,b) memcpy(l,b,Sz(b)) #define pb push_back #define fi first #define se second template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;} template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;} typedef pair<int,int>PII; template<class T>inline void Rd(T &x){ x=0;char c; while((c=getchar())<48); do x=(x<<1)+(x<<3)+(c^48); while((c=getchar())>47); } #define N 100002 int n,q; int A[N]; struct p40{ int tmp[N],cnt; void solve(){ int op,a,b; ll ans; while(q--){ Rd(op),Rd(a),Rd(b); if(op==1)A[a]=b; else { cnt=0; REP(i,a,b)tmp[++cnt]=A[i]; sort(tmp+1,tmp+1+cnt); ans=0; REP(i,1,cnt-2){ REP(j,i+1,cnt-1){ int k=lower_bound(tmp+j+1,tmp+cnt+1,tmp[j])-tmp; if(tmp[i]+tmp[j]>tmp[k])chkmax(ans,(ll)tmp[i]+tmp[j]+tmp[k]); } } printf("%lld\n",ans); } } } }p1; struct p100{ #define lson L,mid,p<<1 #define rson mid+1,R,p<<1|1 struct node{ int L,R; int len,l[50]; }tree[N<<2],ans; node Up(node L,node R){ node res; res.L=L.L,res.R=R.R; res.len=min(47,L.len+R.len); int p1=1,p2=1; REP(i,1,res.len){ if(p1<=L.len && p2<=R.len) res.l[i]=(L.l[p1]>R.l[p2]?L.l[p1++]:R.l[p2++]); else if(p1<=L.len)res.l[i]=L.l[p1++]; else res.l[i]=R.l[p2++]; } return res; } void build(int L,int R,int p){ tree[p].L=L,tree[p].R=R; if(L==R){ tree[p].len=1; tree[p].l[1]=A[L]; return; } int mid=(L+R)>>1; build(lson),build(rson); tree[p]=Up(tree[p<<1],tree[p<<1|1]); } void update(int p,int x,int v){ if(tree[p].L==tree[p].R){ tree[p].l[1]=v; return; } int mid=(tree[p].L+tree[p].R)>>1; if(x<=mid)update(p<<1,x,v); else update(p<<1|1,x,v); tree[p]=Up(tree[p<<1],tree[p<<1|1]); } node query(int L,int R,int p){ if(tree[p].L==L && tree[p].R==R)return tree[p]; int mid=(tree[p].L+tree[p].R)>>1; if(R<=mid)return query(L,R,p<<1); else if(L>mid)return query(L,R,p<<1|1); else return Up(query(lson),query(rson)); } void solve(){ build(1,n,1); int op,a,b; while(q--){ Rd(op),Rd(a),Rd(b); if(op==1)update(1,a,b); else { ans=query(a,b,1); ll res=0; REP(i,3,ans.len) if(ans.l[i]+ans.l[i-1]>ans.l[i-2]) chkmax(res,1ll*ans.l[i]+ans.l[i-1]+ans.l[i-2]); printf("%lld\n",res); } } } }p2; int main(){ // freopen("triangle.in","r",stdin); // freopen("triangle.out","w",stdout); Rd(n),Rd(q); REP(i,1,n)Rd(A[i]); if(n<=100 && q<=100)p1.solve(); else p2.solve(); return 0; }
T3——cactus(3916)
Description:
给出 n n 个点,条边的仅存在简单环的图.求对于每个点,删掉 m−n+1 m − n + 1 条边(即变为一棵树)后的到其它点的最大值的最小值.
n≤500000 n ≤ 500000Solution:
- 对于题面一上来就仙人掌的…表示很虚啊..
- 但是切完分,发现暴力+图本为一棵树的解法差不多就是正解了吧…
- 只不过这里存在简单环.我们先tarjan缩点.这里我顺便就用了圆方树.
- 那么缩点后其实还是一棵树.
- 但是对于要经过环的答案.意义就在于环上的距离的计算.
- 我们不难模拟发现,对于环上的每个点,删掉它的对立的那条边是最优的.
- 即对于环上的每个点.它的最大距离其实就是该点顺时针和逆时针走到对立边的最大值.
- 而这个最大值,我们可以给它依次编号,那么环上两点的距离就是编号差了.
- 但是对于这个 n n 的范围,我们只能线性来做,而枚举两点的复杂度显然是炸的….
- 进一步分析,对于一个环,我们只能以当前点到其它点的距离以及答案传到它的子树下,再在它的子树下统计答案.
- 这里,环上的距离我们不难发现就是维护一个单调队列,这是可以做到的.
- 此题虽然解法简单,但它的实现难度着实脑壳疼啊…
Code:
#include<bits/stdc++.h> using namespace std; #define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i) #define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;++i) #define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i) #define db double #define ll long long #define INF 0x3f3f3f3f #define inf 0x3f3f3f3f3f3f3f #define MINF 0xc0c0c0c0 #define Sz(a) sizeof(a) #define mcl(a,b) memset(a,b,Sz(a)) #define mcp(a,b) memcpy(a,b,Sz(b)) #define pb push_back #define fi first #define se second template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;} template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;} typedef pair<int,int>PII; template<class T>inline void Rd(T &x){ x=0;char c; while((c=getchar())<48); do x=(x<<1)+(x<<3)+(c^48); while((c=getchar())>47); } #define N 1000002 int n,m; int qwq,head[N]; struct edge{ int to,nxt; }E[N<<1]; inline void addedge(int x,int y){E[qwq]=(edge){y,head[x]};head[x]=qwq++;} #define LREP(x) for(int i=head[x];~i;i=E[i].nxt) struct p30{ int dis[2002]; bool vis[2002]; queue<int>Q; void SPFA(int s){ mcl(dis,INF); Q.push(s); vis[s]=1; dis[s]=0; while(!Q.empty()){ int x=Q.front();Q.pop(); vis[x]=0; LREP(x){ int y=E[i].to; if(chkmin(dis[y],dis[x]+1)){ if(!vis[y]){ vis[y]=1; Q.push(y); } } } } } void solve(){ int ans; REP(i,1,n){ SPFA(i); ans=0; REP(j,1,n)chkmax(ans,dis[j]); printf("%d\n",ans); } } }p1; struct p50{ int f[500002][2],g[500002][2]; int max2(int a,int b,int c) { if((a>=b&&a<=c)||(a<=b&&a>=c)) return a; if((b<=a&&b>=c)||(b<=c&&b>=a)) return b; return c; } void dfs1(int x,int fa) { LREP(x){ int y=E[i].to; if(y==fa)continue; dfs1(y,x); chkmax(g[x][1],g[y][0]+1); if(g[x][0]<g[x][1])swap(g[x][0],g[x][1]); } } void dfs2(int x,int fa) { LREP(x){ int y=E[i].to; if(y==fa)continue; if(f[x][0]!=g[y][0]+1) { f[y][0]=f[x][0]+1; f[y][1]=g[x][0]; } else { f[y][0]=max(g[y][0],f[x][1]+1); f[y][1]=max2(g[y][0],g[y][1],f[x][1]+1); } dfs2(y,x); } } void solve(){ dfs1(1,0); f[1][0]=g[1][0]; f[1][1]=g[1][1]; dfs2(1,0); REP(i,1,n)printf("%d\n",f[i][0]); } }p2; struct p100{ int dfn[N],low[N],tim; int stk[N],top; bool vis[N]; int tot; bool mark[N<<1]; int degree[N<<1]; int qaq,Head[N<<1]; struct Edge{ int to,nxt; }G[N<<2]; void Addedge(int x,int y){ G[qaq]=(Edge){y,Head[x]}; Head[x]=qaq++; ++degree[x]; } #define GREP(x) for(int i=Head[x];~i;i=G[i].nxt) int f[N<<1],g[N<<1]; int sec[N<<1],son[N<<1]; void tarjan(int x,int f){ dfn[x]=low[x]=++tim; vis[x]=1; stk[++top]=x; bool flag=0; LREP(x){ int y=E[i].to; if(y==f && !flag){flag=1;continue;} if(!dfn[y]){ tarjan(y,x); if(low[y]>dfn[x]){ Addedge(x,y),Addedge(y,x); top--; } if(low[y]==dfn[x]){ mark[++tot]=1; Addedge(x,tot),Addedge(tot,x); do Addedge(tot,stk[top]),Addedge(stk[top],tot); while(y!=stk[top--]); } chkmin(low[x],low[y]); } else if(vis[y])chkmin(low[x],dfn[y]); } } int dist(int x,int y,int len){ return min(x-y,y-x+len); } void loop1(int x,int fa){ int len=degree[x],id=0; GREP(x){ id++; int y=G[i].to; if(y!=fa) chkmax(f[x],f[y]+dist(len,id,len)); } f[x]--; } void dfs1(int x,int fa){ GREP(x){ int y=G[i].to; if(y==fa)continue; dfs1(y,x); if(!mark[x]){ if(f[x]<f[y]+1){ sec[x]=f[x]; f[x]=f[y]+1; son[x]=y; } else chkmax(sec[x],f[y]+1); } } if(mark[x])loop1(x,fa); } struct Queue { int q[N<<2],id[N<<2],L,R; void init(){L=1;R=0;} void push(int x,int pos){ while (x>q[R] && L<=R)R--; q[++R]=x; id[R]=pos; } int top(){return q[L];} int pos(){return id[L];} void valid(int x) {while (L<=R && id[L]<x)L++;} bool empty(){return R<L;} }Q; int tmp[N<<2]; void loop2(int x,int fa){ g[x]--; int len=degree[x],id=0; Q.init(); GREP(x){ int y=G[i].to; tmp[++id]=y; Q.valid(id-len/2); if(y!=fa && !Q.empty()) chkmax(g[y],Q.top()+id); if(y!=fa) Q.push(f[y]-id,id); else Q.push(g[x]-id,id); } GREP(x){ int y=G[i].to; tmp[++id]=y; Q.valid(id-len/2); if(y!=fa && !Q.empty()) chkmax(g[y],Q.top()+id); if(y!=fa) Q.push(f[y]-id,id); else Q.push(g[x]-id,id); } Q.init(); DREP(i,id,1){ Q.valid(-i-len/2); if(tmp[i]!=fa && !Q.empty()) chkmax(g[tmp[i]],Q.top()-i); if(tmp[i]!=fa) Q.push(f[tmp[i]]+i,-i); else Q.push(g[x]+i,-i); } } void dfs2(int x,int fa){ if(mark[x])loop2(x,fa); GREP(x){ int y=G[i].to; if(y==fa)continue; if(!mark[x]){ chkmax(g[y],g[x]+1); if(son[x]!=y)chkmax(g[y],f[x]+1); else chkmax(g[y],sec[x]+1); } dfs2(y,x); } chkmax(g[x],f[x]); } void solve(){ tot=n; qaq=0; mcl(Head,-1); REP(i,1,n) if(!dfn[i]) tarjan(i,0); dfs1(1,0); dfs2(1,0); REP(i,1,n) printf("%d\n",g[i]); } }p3; int main(){ // freopen("cactus.in","r",stdin); // freopen("cactus.out","w",stdout); qwq=0; mcl(head,-1); Rd(n),Rd(m); REP(i,1,m){ int a,b; Rd(a),Rd(b); addedge(a,b); addedge(b,a); } if(n==m+1)p2.solve(); else if(n<=2000)p1.solve(); else p3.solve(); return 0; }
Summary:
- T1 T 1 的思维难度着实蛋疼…但也不妨是一种套路…
- T2 T 2 还是一道比较正常的线段树,虽然不是 NOIP N O I P 范围内.
- T3 T 3 是真毒瘤…实现难度奇大无比…细节超多…但题型还是比较正常的..
- 综上,题目都是中等偏难的,就是 T3 T 3 的码量也是大得不要不要的…
- 评价:较毒瘤出题人.
-
op=2
o
p
=
2
,l,r.对区间
[l,r]
[
l
,
r
]
进行询问最大的三角形周长.