版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Caristra/article/details/82693698
T1——gcd(3915)
Description:
给你两个数
,
,求
.特殊地,
.
Solution:
- 关于此题,不知道是被题面误导要因式分解,还是被NOIP2017D1T1所敏感地去打表…
- 反正一开始就没想到正解上,接近自闭…
- 但当开始走投无路的去肉模拟这个玩意的时候 ,发现推了一次得到 ,就感觉这个好像就是将 肉拆一次,再次 …
- 真的无语…有点脑筋急转弯的味道…
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:
有一个长度为
的序列{
},表示木棒的长度.我们将用这些木棒拼出周长最大的三角形.
那么有
个操作.
- , , .将
-
,l,r.对区间
进行询问最大的三角形周长.
Solution:
- 对于三角形的周长问题,最近也是频繁遇到.
- 而此题是带单点修改的.那么显然是用线段树解决.
- 那么线段树的关键还是合并问题.
- 我们发现,在树上直接存答案是不太现实的.
- 那么我们只能是存该区间的一些木棒.
- 而我们要的是最大的周长,那么关键字一定是 .
- 这里,我觉得自己的做法还是偏无脑的做法.
- 因为分析修改的 ,对于每个区间影响的 ,其实是只有 个.
- 那么我们就在树上存上每个区间的前 大 即可.
- 最后询问暴力来取 .
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:
给出
个点,
条边的仅存在简单环的图.求对于每个点,删掉
条边(即变为一棵树)后的到其它点的最大值的最小值.
Solution:
- 对于题面一上来就仙人掌的…表示很虚啊..
- 但是切完分,发现暴力+图本为一棵树的解法差不多就是正解了吧…
- 只不过这里存在简单环.我们先tarjan缩点.这里我顺便就用了圆方树.
- 那么缩点后其实还是一棵树.
- 但是对于要经过环的答案.意义就在于环上的距离的计算.
- 我们不难模拟发现,对于环上的每个点,删掉它的对立的那条边是最优的.
- 即对于环上的每个点.它的最大距离其实就是该点顺时针和逆时针走到对立边的最大值.
- 而这个最大值,我们可以给它依次编号,那么环上两点的距离就是编号差了.
- 但是对于这个 的范围,我们只能线性来做,而枚举两点的复杂度显然是炸的….
- 进一步分析,对于一个环,我们只能以当前点到其它点的距离以及答案传到它的子树下,再在它的子树下统计答案.
- 这里,环上的距离我们不难发现就是维护一个单调队列,这是可以做到 的.
- 此题虽然解法简单,但它的实现难度着实脑壳疼啊…
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:
- 的思维难度着实蛋疼…但也不妨是一种套路…
- 还是一道比较正常的线段树,虽然不是 范围内.
- 是真毒瘤…实现难度奇大无比…细节超多…但题型还是比较正常的..
- 综上,题目都是中等偏难的,就是 的码量也是大得不要不要的…
- 评价:较毒瘤出题人.