Codeforces Round #613 选讲
http://codeforces.com/contest/1285/problem/D
从高位往低位看,如果某一位上全是一样的数字,则直接看下一位;如果某位上有0有1,表明这一位答案上一定有个1,但具体那个X是要取0还是取1,取决于后面的位数,由此可将数字按这一位的01分成两组,递归地解决问题。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int n; 5 #define maxn 200011 6 int a[maxn]; 7 8 int dfs(int x,int L,int R) 9 { 10 if (x<0) return 0; 11 if (((a[R]>>x)&1)==0 || ((a[L]>>x)&1)==1) return dfs(x-1,L,R); 12 int mid=L; for (;mid<=R && ((a[mid]>>x)&1)==0;mid++); 13 return (1<<x)+min(dfs(x-1,L,mid-1),dfs(x-1,mid,R)); 14 } 15 16 int main() 17 { 18 scanf("%d",&n); 19 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 20 sort(a+1,a+1+n); 21 printf("%d\n",dfs(29,1,n)); 22 return 0; 23 }
http://codeforces.com/contest/1285/problem/E
思路点在于找到“删除后会增加/减少的那些线段并后的区间”,即什么情况下,删除某个区间后,并后的区间与初始的并相比会变多/变少。变多:对一个坐标x,如果此时x为某个线段的起点,且x刚好被且只被某线段i覆盖,则删去i后区间数+1。变少:如果某条线段的左端点本来就是初始并的某个左端点,那么删去之后会比初始并少去一个区间(当然可能还有新增加的,这由前一种情况统计)。采用扫描线的方法完成,把一个线段拆成两个修改操作,按坐标排序后分别统计初始答案和以上两种情况。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int T,n,lq; 5 #define maxn 400011 6 struct SEG{int l,r;}a[maxn]; 7 struct QUES 8 { 9 int x,id,ty; 10 bool operator < (const QUES &b) const {return x<b.x || (x==b.x && ty>b.ty);} 11 }q[maxn<<1]; 12 void addq(int x,int id,int ty) {q[++lq]=(QUES){x,id,ty};} 13 int diff[maxn]; 14 set<int> s; 15 int main() 16 { 17 scanf("%d",&T); 18 while (T--) 19 { 20 scanf("%d",&n); 21 lq=0; 22 for (int i=1;i<=n;i++) scanf("%d%d",&a[i].l,&a[i].r),addq(a[i].l,i,1),addq(a[i].r,i,-1); 23 sort(q+1,q+1+lq); 24 25 memset(diff,0,sizeof(diff)); 26 int cnt=0,init=0; 27 for (int i=1,j,k;i<=lq;) 28 { 29 bool flag=(cnt==0); 30 j=i; 31 while (j<=lq && q[j].x==q[i].x) j++; 32 k=i; 33 for (;q[k].ty==1 && k<j;k++) cnt++; 34 if (flag && cnt==1) diff[q[i].id]--; 35 for (;q[k].ty==-1 && k<j;k++) cnt--; 36 if (cnt==0) init++; 37 i=j; 38 } 39 40 s.clear(); 41 for (int i=1,j,k;i<=lq;) 42 { 43 int add=(s.size()==1?(*s.begin()):-1); 44 j=i; 45 while (j<=lq && q[j].x==q[i].x) j++; 46 k=i; 47 for (;q[k].ty==1 && k<j;k++) s.insert(q[k].id); 48 if (s.size()>1 && ~add) diff[add]++; 49 for (;q[k].ty==-1 && k<j;k++) s.erase(s.lower_bound(q[k].id)); 50 i=j; 51 } 52 53 int ans=0; 54 for (int i=1;i<=n;i++) ans=max(ans,init+diff[i]); 55 printf("%d\n",ans); 56 } 57 return 0; 58 }
http://codeforces.com/contest/1285/problem/F
枚举gcd,每次只考虑gcd的倍数(复杂度允许),将它们分别除以gcd后,在其中找乘积最大的互质的两个数。可以将它们从大到小排序入栈,每次一个数x入栈后,若监测到栈中存在与他互质的数就不停弹栈,弹到没有为止,最后弹出去的那个就是与x互质且最大的数。与x互质的数的数量即$\sum_{d|x} \mu(d) \times cnt_d$,其中$cnt_d$为$d$的倍数个数(可以考虑两数互质的情况然后推广可得此式)。每次可枚举x的约数计算(复杂度++)。总复杂度为每个数约数个数的平方之和。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 5 int n; 6 #define maxn 200011 7 #define MAXNUM 100000 8 int a[maxn]; 9 bool cmp(int a,int b) {return a>b;} 10 11 vector<int> Div[maxn],mul[maxn]; 12 int miu[maxn],pri[maxn],lp=0; bool vis[maxn]; 13 void makeprime(int n) 14 { 15 miu[1]=1; 16 for (int i=2;i<=n;i++) 17 { 18 if (!vis[i]) pri[++lp]=i,miu[i]=-1; 19 for (int j=1;j<=lp && 1ll*i*pri[j]<=n;j++) 20 { 21 vis[i*pri[j]]=1; 22 miu[i*pri[j]]=-miu[i]; 23 if (i%pri[j]==0) {miu[i*pri[j]]=0; break;} 24 } 25 } 26 } 27 28 int top=0,sta[maxn],cnt[maxn]; 29 30 int main() 31 { 32 scanf("%d",&n); 33 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 34 sort(a+1,a+1+n,cmp); 35 36 for (int i=1;i<=MAXNUM;i++) 37 for (int j=i;j<=MAXNUM;j+=i) 38 Div[j].push_back(i); 39 40 for (int i=1;i<=n;i++) 41 for (int j=0;j<Div[a[i]].size();j++) 42 mul[Div[a[i]][j]].push_back(a[i]/Div[a[i]][j]); 43 44 makeprime(MAXNUM); 45 46 LL ans=0; 47 for (int i=1;i<=MAXNUM;i++) if (mul[i].size()>0) 48 { 49 top=0; 50 for (int j=0,now,last;j<mul[i].size();j++) 51 { 52 last=0; now=mul[i][j]; 53 while (1) 54 { 55 int tot=0; 56 for (int k=0;k<Div[now].size();k++) tot+=miu[Div[now][k]]*cnt[Div[now][k]]; 57 if (tot>0) 58 { 59 last=sta[top]; 60 for (int k=0;k<Div[last].size();k++) cnt[Div[last][k]]--; 61 top--; 62 } 63 else 64 { 65 ans=max(ans,1ll*last*now*i); 66 break; 67 } 68 } 69 sta[++top]=now; 70 for (int k=0;k<Div[now].size();k++) cnt[Div[now][k]]++; 71 } 72 while (top) 73 { 74 int last=sta[top]; 75 for (int k=0;k<Div[last].size();k++) cnt[Div[last][k]]--; 76 top--; 77 } 78 } 79 80 printf("%lld\n",ans); 81 return 0; 82 }