水
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int maxn=1e3+10; struct node{ ll num,mag; friend bool operator <(const node &a,const node &b){ return a.mag>b.mag; } }a[maxn]; int n; ll p[70]; ll add(ll x,ll val){ for(int i=60;i>=0;i--) { if(x&(1<<i)) { if(!p[i]){ p[i]=x; break; }else{ x=x^p[i]; } } } if(x>0)return val; return 0; } int main(){ while(cin>>n) { ll l,r,d; while(n--) { cin>>l>>r>>d; if(d<l)printf("%lld ",d); else{ printf("%lld ",(r/d+1)*d); } } } }
小模拟,从前往后扫到第一个 [: ,从后往前扫到第一个 :] ,然后数中间的 “|” 就可以了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int maxn=5e5+10; char s[maxn]; int main(){ while(scanf("%s",s+1)!=EOF) { int flag=0,p1=-1,p2=-1,len=strlen(s+1); for(int i=1;i<=len;i++) { if(flag==0) { if(s[i]=='[')flag=1; }else{ if(s[i]==':'){ p1=i; break; } } } flag=0; for(int i=len;i>p1&&i>0;i--) { if(flag==0) { if(s[i]==']')flag=1; }else{ if(s[i]==':'){ p2=i; break; } } } if(p1==-1||p2==-1){ printf("-1 "); continue; } int tot=0; for(int i=p1+1;i<p2;i++) { if(s[i]=='|')tot++; } printf("%d ",tot+4); } }
题意:把给出的区间分成两部分,使不同部分的区间,不会有交点。
按 l 排序一遍,如果 l 小于前面最大的 r ,则必须和前面分在同一个群,否则就到第二个群。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int maxn=2e5+10; int T,n; struct node{ int l,r; int id; friend bool operator <(const node &a,const node &b) { return a.l<b.l; } }a[maxn]; int ans[maxn]; int main(){ cin>>T; while(T--) { cin>>n; for(int i=1;i<=n;i++) { scanf("%d%d",&a[i].l,&a[i].r); a[i].id=i; } sort(a+1,a+1+n); int maxx=a[1].r,tep=0,flag=0; ans[a[1].id]=1; for(int i=2;i<=n;i++) { if(a[i].l<=maxx){ ans[a[i].id]=1+tep; }else{ ans[a[i].id]=1+1-tep; tep=1-tep; flag=1; } maxx=max(maxx,a[i].r); } if(flag==0)puts("-1"); else{ for(int i=1;i<=n;i++) { printf("%d%c",ans[i]," "[i==n]); } } } }
题意:给出一颗点带权的数,求任意两点简单路径上的点gcd大于1的长度最大是多少。
题解:
gcd大于1即不互质,若一条路径是合法路径,则必定有一个大于1的公共质因子。所以我们可以对每个小于2e5的质数重新建树,然后再求树的直径。
建图是怎么建的呢,其实只要把边读入的时候,就把边塞到各自的质因子背包里面去,最后把每个背包的边都建立出来,跑树上直径。
但是有一个问题是,小于2e5的质数有一万多个,树的直径又是O(n)的,这样看上去会超时,我也困扰了好久。其实,两个点之间的公共gcd的质因子个数最多就十个左右,(再多就爆了)也就意味着每个点最多被建图十次,所以如果跑树的直径最后的总计算次数也就是10*O(n)左右,不会超时,这类问题以后要注意,明明很快就想到标算的,但迟迟不敢动手。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int maxn=2e5+10; int prim[maxn],n,u,v,a[maxn]; int gcd(int a,int b){ return b==0?a:gcd(b,a%b); } void initPrim(){ for(int i=2;i<=2e5/2;i++) { for(int j=2;i*j<=2e5;j++) { prim[i*j]=1; } } } struct edge{ int u,v; }; vector<edge>ve[maxn]; vector<int >e[maxn]; vector<int >jont; bool vis[maxn]; int ans=0; int dfs(int u,int fa,int dep){ vis[u]=1; int f=0; int flink=0,slink=0; for(int i=0;i<e[u].size();i++) { int v=e[u][i]; if(v==fa)continue; f=1; int tep=dfs(v,u,dep+1); if(tep>flink)slink=flink,flink=tep; else if(tep>slink)slink=tep; } ans=max(ans,max(dep+flink,flink+1+slink)); return flink+1; } int main(){ initPrim(); while(cin>>n) { ans=1; int fff=0; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(a[i]>1)fff=1; } for(int i=2;i<=2e5;i++)ve[i].clear(); for(int i=1;i<n;i++) { scanf("%d%d",&u,&v); int k=gcd(a[u],a[v]); if(k>1){ for(int j=1;j*j<=k;j++) { if(k%j==0) { if(j!=1&&prim[j]==0) ve[j].push_back({u,v}); if(j*j!=k&&prim[k/j]==0) ve[k/j].push_back({u,v}); } } } } if(fff==0){ puts("0"); continue; } clr(vis,1); for(int i=2;i<=2e5;i++) { if(!prim[i]) { for(int j=0;j<ve[i].size();j++) { if(vis[ve[i][j].u]==1) { jont.push_back(ve[i][j].u); } if(vis[ve[i][j].v]==1) { jont.push_back(ve[i][j].v); } vis[ve[i][j].u]=0; vis[ve[i][j].v]=0; e[ve[i][j].u].push_back(ve[i][j].v); e[ve[i][j].v].push_back(ve[i][j].u); } for(int j=0;j<jont.size();j++) { vis[jont[j]]=0; } for(int j=0;j<jont.size();j++) { int u=jont[j]; if(!vis[u]){ dfs(u,0,1); } } for(int j=0;j<jont.size();j++) { e[jont[j]].clear(); } jont.clear(); } } cout<<ans<<endl; } }
为什么这会是E题,一开始我以为是求有几张钞票能被塞进去,看了样例才发现我想太多了。
反正就钞票放进去的时候,固定格式,短的一边在下面,钱包也是这样,分别记录长边和短边的最大值,比一下即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int maxn=2e5+10; int T,n; struct node{ int l,r; int id; friend bool operator <(const node &a,const node &b) { return a.l<b.l; } }a[maxn]; int ans[maxn]; int main(){ cin>>T; int maxl=0,maxr=0,l,r; char op[3]; while(T--) { scanf("%s%d%d",op,&l,&r); if(op[0]=='+'){ if(l>r)swap(l,r); maxl=max(maxl,l),maxr=max(maxr,r); }else{ if(l>r)swap(l,r); if(l>=maxl&&r>=maxr)printf("YES "); else puts("NO"); } } }
好题,题解移步我的另外一篇博客 点这里
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int maxn=402; ll ans; int dp[maxn][maxn][maxn],a[maxn]; int n,m; int main(){ while(cin>>n>>m) { ans=0; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } for(int i=1;i<=n;i++) { for(int j=i;j<=n;j++) { dp[i][j][0]=a[j]-a[i]; } } for(int k=1;k<=n;k++) { for(int i=1;i<=n;i++) { int w=i; for(int j=i;j<=n;j++) { while(w<j&&max(dp[i][w][k-1],a[j]-a[w])>max(dp[i][w+1][k-1],a[j]-a[w+1]))w++; dp[i][j][k]=max(dp[i][w][k-1],a[j]-a[w]); } } } int s,f,r; ll c; while(m--) { scanf("%d%d%lld%d",&s,&f,&c,&r); ans=max(ans,dp[s][f][r]*c); } cout<<ans<<endl; } }
题意:给出一个序列,试将其划分为尽可能多的非空子段,满足每一个元素出现且仅出现在其中一个子段中,且在这些子段中任取若干子段,它们包含的所有数的异或和不能为0.
思路:先处理出前缀异或,这样选择更多的区间其实就相当于选择更多的前缀异或,并且这些前缀异或不能异或出0,这就变成了线性基的基础题了。贪心的放,能放就放。不能放就意味着线性基的add函数里面的val最后变成了0,也就是当前已经插入的线性基已经可以异或出正在插入的数了,所以不能放。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int maxn=2e5+10; ll a[maxn],p[40],s[maxn]; int n; int add(ll val){ for(int i=30;i>=0;i--) { if(val&(1<<i)){ if(!p[i]){ p[i]=val; return 1; } val^=p[i]; } } return 0; } int main(){ while(cin>>n) { clr(p,0); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); s[i]=s[i-1]^a[i]; } if(s[n]==0){ puts("-1"); continue; } int ans=0; for(int i=n;i>0;i--) { ans+=add(a[i]); } cout<<ans<<endl; } }