文章目录
- 前言
- CF1227A Math Problem
- CF1227B Box
- CF1227C Messy
- CF1227D Optimal Subsequences
- CF1227E Arson In Berland Forest
- CF1227F Wrong Answer on test 233
- Description\text{Description}Description
- Solution\text{Solution}Solution
- easy version
- hard version
- Code\text{Code}Code
- CF1227G Not Same
- CF1261F Xor-Set
前言
三倍经验
(为了方便,均按洛谷题号)
1227ABC是水题
D是小清新数据结构
E是之前考过的题,但是没了不碰边界的条件,细节稍微要更多一些
F1是垃圾dp,F2是降智数学题(水紫!)
G是很神奇的构造题
1261F是神仙线段树题,实现起来倒不难,主要是难以想到
CF1227A Math Problem
Description\text{Description}Description
给出 nnn 条线段(含端点),请你给出一条最短的线段,使其与所有线段都有交,输出最短的长度(r−lr-lr−l).
n≤105n\le10^5n≤105
Solution\text{Solution}Solution
要求均有交的充要条件是:l≤minri∧r≥maxlil\le\min r_i\land r\ge\max l_il≤minri∧r≥maxli.
所以答案就是 max(0,maxli−minri)\max(0,\max l_i-\min r_i)max(0,maxli−minri).
Code\text{Code}Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=5e5+100;
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
int n,m,k;signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifint T=read();while(T--){int l=2e9,r=-2e9;n=read();for(int i=1;i<=n;i++){int x=read(),y=read();l=min(l,y);r=max(r,x);}r=max(l,r);printf("%d\n",r-l);}return 0;
}
/**/
CF1227B Box
Description\text{Description}Description
有一个长度为 nnn 的排列 q1...nq_{1...n}q1...n,定义 pi=maxj≤iqjp_i=\max_{j\le i} q_jpi=maxj≤iqj,现在给出 p1...n(pi≥pi−1)p_{1...n}(p_i\ge p_{i-1})p1...n(pi≥pi−1),请你构造一个合法的 qqq 或者报告无解.
n≤105n\le 10^5n≤105
Solution\text{Solution}Solution
显然,最大值改变的位置必然就是最大值.
剩下的位置从前往后贪心的先填小的即可.
如果和最大值条件矛盾则无解.
Code\text{Code}Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=2e5+100;
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
int n,m,k;
int vis[N];
int ans[N],mx[N];
signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifint T=read();while(T--){int now=0;n=read();fill(vis,vis+1+n,0);fill(ans,ans+1+n,0);for(int i=1;i<=n;i++){mx[i]=read();if(mx[i]>now){now=mx[i];ans[i]=mx[i];vis[mx[i]]=1;//printf("i=%d mx=%d\n",i,mx[i]);}}int pl=1,flag=0;for(int i=1;i<=n;i++){if(ans[i]) continue;while(vis[pl]) ++pl;//printf("i=%d pl=%d\n",i,pl);ans[i]=pl;vis[pl]=1;if(ans[i]>mx[i]){flag=1;printf("-1\n");break;}}if(!flag){for(int i=1;i<=n;i++) printf("%d ",ans[i]);putchar('\n');} }return 0;
}
/**/
CF1227C Messy
Description\text{Description}Description
给出一个长度为 nnn 的括号序列,你每次可以翻转一个区间,请在 nnn 次操作内使序列变为合法序列且恰好有 kkk 个前缀是合法前缀(包括本身).
保证存在合法解.
n≤2000n\le2000n≤2000
Solution\text{Solution}Solution
令前 k−1k-1k−1 个都是 ()()() 的形状,然后填成 (((((...)))))(((((...)))))(((((...))))) 即可.
n2n^2n2 暴力就可过.
(预处理一些东西应该可以线性,但是懒得打了).
Code\text{Code}Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=2e5+100;
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
int n,m,k;
char s[N];
int l,r;
signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifint T=read();while(T--){n=read();k=read();scanf(" %s",s+1);--k;int x=n/2,y=n/2;printf("%d\n",n);for(int i=1;i<=n;i++){if((k>0&&i%2==0)||(!x)){l=r=i;while(s[r]=='(') ++r;printf("%d %d\n",l,r);swap(s[l],s[r]);--k;--y;}else{l=r=i;while(s[r]==')') ++r;printf("%d %d\n",l,r);swap(s[l],s[r]);--x;}}}return 0;
}
/**/
CF1227D Optimal Subsequences
Description\text{Description}Description
给定一个长度为 nnn 的正整数序列 a1,a2,...,ana_1,a_2,...,a_na1,a2,...,an。
有 mmm 个询问,每次询问给出两个正整数 k,posk,posk,pos。你需要找到一个长度为 kkk 的子序列,且满足如下要求:
- 该子序列的元素和是所有子序列中最大的;
- 该子序列是所有满足上一条件的子序列中字典序最小的一个。
对于每个询问,输出该子序列的第 pospospos 个元素的值。
1≤n,m≤2×1051 \le n,m \le 2\times10^51≤n,m≤2×105(这是与困难版本唯一的区别), 1≤k≤n\ 1 \le k \le n 1≤k≤n,在同一询问中有 1≤pos≤k1 \le pos \le k1≤pos≤k。
Solution\text{Solution}Solution
一种主席树实现的在线做法.
设选出的子序列的最小值为 mnmnmn,那么必然是大于 mnmnmn 的全部选,等于 mnmnmn 的元素尽量靠前选.
设 mnmnmn 在当前序列中共出现了 numnumnum 次.
考虑二分答案,利用主席树询问前面在给定能否选到的数的个数是否达到 kkk 次,注意 mnmnmn 最多取 numnumnum 个.
Code\text{Code}Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=2e5+100;
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
int n,m,k;
int a[N],q[N],cnt,sum[N],ori[N];
#define mid ((l+r)>>1)
struct tree{int siz,ls,rs;
}tr[N<<5];
int rt[N],tot;
inline int copy(int x){tr[++tot]=tr[x];return tot;
}
void upd(int &k,int l,int r,int p){ k=copy(k);//debug("k=%d (%d %d) p=%d\n",k,l,r,p);if(l==r){tr[k].siz++;return;}if(p<=mid) upd(tr[k].ls,l,mid,p);else upd(tr[k].rs,mid+1,r,p);tr[k].siz=tr[tr[k].ls].siz+tr[tr[k].rs].siz;return;
}
int ask(int k,int l,int r,int x,int y){if(!k||x>y) return 0;if(x<=l&&r<=y) return tr[k].siz;int res=0;if(x<=mid) res+=ask(tr[k].ls,l,mid,x,y);if(y>mid) res+=ask(tr[k].rs,mid+1,r,x,y);return res;
}
bool cmp(int x,int y){return x>y;}
signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=read();for(int i=1;i<=n;i++) q[i]=a[i]=read();sort(q+1,q+1+n);cnt=unique(q+1,q+1+n)-q-1;for(int i=1;i<=n;i++) a[i]=lower_bound(q+1,q+1+cnt,a[i])-q;for(int i=1;i<=n;i++){sum[a[i]]++;rt[i]=rt[i-1];upd(rt[i],1,cnt,a[i]);}for(int i=cnt;i>=1;i--) sum[i]+=sum[i+1];memcpy(ori,a,sizeof(a));sort(a+1,a+1+n,cmp);m=read();for(int i=1;i<=m;i++){int k=read(),pos=read();int mn=a[k],num=k-sum[mn+1];//printf("mn=%d num=%d\n",mn,num);int st=1,ed=n;while(st<ed){int mmid=(st+ed)>>1;if(ask(rt[mmid],1,cnt,mn+1,cnt)+min(num,ask(rt[mmid],1,cnt,mn,mn))>=pos) ed=mmid;else st=mmid+1; }printf("%d\n",q[ori[st]]);}return 0;
}
/**/
CF1227E Arson In Berland Forest
Description\text{Description}Description
在一个无限大的矩阵中,每个位置是一棵树。在一个 n×mn \times mn×m 的子矩阵中,发生了一场火灾,一些树被摧毁了。被摧毁的树用字符 X
表示,未被摧毁的树用字符 .
表示。子矩阵外的树都没有被摧毁.
- 在 000 时刻,有些树是自发着火的.
- 接下来的每一分钟内,每一棵着火(也即,被摧毁)的树,会使得它周围的 888 个相邻的树着火.
- 在第 TTT 分钟初,火灾停止.
现在给定最后被摧毁的树,求最大可能的 TTT,并求出任意一种满足的、自发着火的树的集合.
Solution\text{Solution}Solution
bfs 预处理出每个燃烧点到外部的最短距离 disdisdis.
二分时间 ttt,那么 dis≥tdis\ge tdis≥t 的点是可以初始燃烧的.
从可以初始燃烧的所有点 bfs ttt 次,若 bfs 的地图和原图一致,则合法.
注意边界的树是完好的.
Code\text{Code}Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=3e6+100;
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
int n,m,k;
#define id(a,b) ((a)*(m+2)+(b))
bool vis[N];
int mp[N],dis[N];
int dx[9]={0,-1,-1,-1,0,1,1,1,0},dy[9]={0,-1,0,1,1,1,0,-1,-1};
#define pr pair<int,int>
#define mkp make_pair
pr q[N];
int st,ed;
void bfs(){st=1;ed=0;for(int i=0;i<=n+1;i++){for(int j=0;j<=m+1;j++){if(!mp[id(i,j)]){vis[id(i,j)]=1;q[++ed]=mkp(i,j);}}}while(st<=ed){int x=q[st].first,y=q[st].second;++st;//printf("(%d %d)\n",x,y);for(int i=1;i<=8;i++){int xx=x+dx[i],yy=y+dy[i];if(xx<1||xx>n||yy<1||yy>m) continue;if(vis[id(xx,yy)]) continue;//printf(" ->(%d %d)\n",xx,yy);vis[id(xx,yy)]=1;dis[id(xx,yy)]=dis[id(x,y)]+1;q[++ed]=mkp(xx,yy);}}return;
}
int a[N];
bool check(int k){st=1,ed=0;memset(vis,0,sizeof(vis));for(int i=1;i<=n;i++){for(int j=1;j<=m;j++) if(dis[id(i,j)]>=k) q[++ed]=mkp(i,j),vis[id(i,j)]=1;}//for(int i=1;i<=n;i++){//for(int j=1;j<=m;j++) printf("%d",vis[id(i,j)]);//putchar('\n');//}for(int ned=ed,i=1;i<k;i++,ed=ned){while(st<=ed){int x=q[st].first,y=q[st].second;++st;for(int i=1;i<=8;i++){int xx=x+dx[i],yy=y+dy[i];if(xx<1||xx>n||yy<1||yy>m) return false;if(vis[id(xx,yy)]) continue;vis[id(xx,yy)]=1;q[++ned]=mkp(xx,yy);}}}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++) if(vis[id(i,j)]^mp[id(i,j)]) return false;}return true;
}
signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=read();m=read();char c;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){scanf(" %c",&c);mp[id(i,j)]=c=='X';}}bfs();//printf("%d\n",check(2));//return 0;int st=1,ed=max(n,m);while(st<ed){int mid=(st+ed+1)>>1;if(check(mid)) st=mid;else ed=mid-1;} printf("%d\n",st-1);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(dis[id(i,j)]>=st) putchar('X');else putchar('.');}putchar('\n');}return 0;
}
/*
*/
CF1227F Wrong Answer on test 233
Description\text{Description}Description
有 nnn 道题,你的程序在上交答案时把答案交串了,第 iii 个答案变成了第 i%n+1i\%n+1i%n+1 个.
给出 nnn 道题的正确答案以及选项数 kkk ,求有多少中初始上交的答案,能使交串后正确的题目数变多.
Solution\text{Solution}Solution
easy version
n≤2000,k≤109n\le2000,k\le10^9n≤2000,k≤109
设计 dpi,jdp_{i,j}dpi,j 表示填到第 iii 题,多填对了 jjj 道题的方案数.
暴力转移即可.
hard version
n≤2×105,k≤109n\le2\times10^5,k\le10^9n≤2×105,k≤109
原来 dp 的做法行不通了,我们需要另辟蹊径.
设 fif_ifi 表示多对了 iii 道题的方案数,由于对称性,有 fi=f−if_i=f_{-i}fi=f−i.
所以我们的答案其实就是:
kn−f02\dfrac{k^n-f_0}{2}2kn−f0
所以我们只需要求出 f0f_0f0 就行了.
连续两个答案相同无法产生差异,我们扫一遍求出有 mmm 个位置可以产生差异.
枚举答对(答错)的题目数,则有:
f0=∑i=0⌊m2⌋kn−m×Cmi×Cm−1i×(k−2)m−2if_0=\sum_{i=0}^{\lfloor\frac{m}{2}\rfloor}k^{n-m}\times C_m^i\times C_{m-1}^i\times (k-2)^{m-2i}f0=i=0∑⌊2m⌋kn−m×Cmi×Cm−1i×(k−2)m−2i
直接求解即可.
Code\text{Code}Code
dp:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=2050;
const int mod=998244353;
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
int n,m,k;
ll dp[2][N<<1];
int now,nxt,o=2000,a[N];
signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=read();k=read();for(int i=1;i<=n;i++) a[i]=read();dp[nxt=1][0+o]=1;for(int i=1;i<=n;i++){swap(now,nxt);memset(dp[nxt],0,sizeof(dp[nxt]));for(int j=-i;j<=i;j++){if(a[i]==a[i%n+1]) (dp[nxt][j+o]+=dp[now][j+o]*k)%=mod;else{(dp[nxt][j+1+o]+=dp[now][j+o])%=mod;(dp[nxt][j-1+o]+=dp[now][j+o])%=mod;(dp[nxt][j+o]+=(k-2)*dp[now][j+o])%=mod;}}}ll res(0);for(int i=1;i<=n;i++) (res+=dp[nxt][i+o])%=mod;printf("%lld\n",res);return 0;
}
/*
*/
组合数:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=2e5+100;
const int mod=998244353;
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
int n,m,k;
int a[N];
ll ans;
ll ksm(ll x,ll k){ll res=1;while(k){if(k&1) res=res*x%mod;x=x*x%mod;k>>=1;}return res;
}
ll jc[N],ni[N],mi[N];
inline ll C(int n,int m){return jc[n]*ni[m]%mod*ni[n-m]%mod;
}
signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=read();k=read();if(k==1){printf("0");return 0;}for(int i=1;i<=n;i++) a[i]=read();for(int i=1;i<=n;i++) m+=(a[i]!=a[i%n+1]);jc[0]=1;for(int i=1;i<=m;i++) jc[i]=jc[i-1]*i%mod;ni[m]=ksm(jc[m],mod-2);for(int i=m-1;i>=0;i--) ni[i]=ni[i+1]*(i+1)%mod;mi[0]=1;for(int i=1;i<=n;i++) mi[i]=mi[i-1]*(k-2)%mod;ans=ksm(k,n);ll w=ksm(k,n-m);for(int i=0;i<=m/2;i++) ans=(ans+mod-w*C(m,i)%mod*C(m-i,i)%mod*mi[m-2*i]%mod)%mod;ans*=ksm(2,mod-2);ans%=mod;printf("%lld\n",ans);return 0;
}
/*
*/
CF1227G Not Same
Description\text{Description}Description
给定大小为 nnn 的序列 aaa , 满足 1⩽ai⩽n1 \leqslant a_i \leqslant n1⩽ai⩽n.
你需要执行至多 n+1n+1n+1 次操作使得所有数变为 000 ,每次操作你可以把一个子集的元素都 −1-1−1 , 要求每次操作的子集互不相同.
n⩽1000n\leqslant 1000n⩽1000.
Solution\text{Solution}Solution
把所有元素从大到小排序.
排序后的第 iii 个元素从第 iii 行开始连续填,到头循环即可.
为什么这样必然合法?
首先不难发现,这样填完之后后一列最多比前一列的下部低一位.
假设第 iii 行和第 jjj 行完全相同. (i<j)(i<j)(i<j)
那么由于第 iii 行的第 i+1i+1i+1 列没有数,那么第 jjj 行的第 i+1i+1i+1 列也没有数.
那么第 i+2i+2i+2 列最多比 i+1i+1i+1 列往下一行,不可能同时让第 iii 列和第 jjj 列有数,也只能让两列都没有数.
以此类推,最后到第 jjj 列的时候,第 jjj 行第 jjj 列必然有数(元素为正数),但第 iii 行第 jjj 列却没有数,矛盾.
原命题得证.
Code\text{Code}Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=1050;
const int mod=998244353;
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
int n,m,k;
int a[N],x[N];
bool cmp(int x,int y){return a[x]>a[y];}
int ans[N][N];
signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=read();for(int i=1;i<=n;i++) a[i]=read(),x[i]=i;sort(x+1,x+1+n,cmp);for(int i=1;i<= n;i++){int now=x[i];for(int j=i;a[now];j=j%(n+1)+1) ans[j][now]=1,a[now]--;}printf("%d\n",n+1);for(int i=1;i<=n+1;i++){for(int j=1;j<=n;j++) printf("%d",ans[i][j]);putchar('\n');}return 0;
}
/*
*/
CF1261F Xor-Set
Description\text{Description}Description
给出两个整数集合 A,BA,BA,B,求所有使得存在 a∈A,b∈Ba \in A,b \in Ba∈A,b∈B 且 a⊕b=ca \oplus b=ca⊕b=c 的整数 ccc 之和取模 998244353998244353998244353 的值,其中 ⊕\oplus⊕ 表示按位异或,即 xor
.
对于 AAA,给出 nAn_AnA,然后给出 nAn_AnA 个区间 [li,ri][l_i,r_i][li,ri],表示对于所有满足 li≤a≤ril_i \le a \le r_ili≤a≤ri 的整数 aaa 都有 a∈Aa \in Aa∈A(即 [li,ri]∈A[l_i,r_i] \in A[li,ri]∈A)。对于 BBB 以同样方式给出其中的元素.
A,BA,BA,B 都是不重集,即每个整数至多在集合中出现一次(虽然对题意没有影响).
数据范围:1≤nA,nB≤100,1≤li,ri≤10181 \le n_A,n_B \le 100,1 \le l_i,r_i \le 10^{18}1≤nA,nB≤100,1≤li,ri≤1018.
Solution\text{Solution}Solution
每个区间可以转化为 O(logn)O(logn)O(logn) 个形如 [l,l+2k−1][l,l+2^k-1][l,l+2k−1] 的连续区间.
注意到,当两个这样的区间异或时,结果还是一个连续区间,而且易于求解.
直接拆的话复杂度是 O(n2log21018)O(n^2log^210^{18})O(n2log21018).
考虑优化.
注意到,若长度为 xxx 的区间 AAA 与 长度为 yyy 的区间 BBB 异或(x≥y)x\ge y)x≥y),结果等价于区间 AAA 与包含区间 BBB 的长度同样为 xxx 的区间异或.
所以我们上线段树,每次令一个集合存入所有线段经过的所有区间,另一个集合存入所有线段包含的所有区间,对同一深度的区间异或即可.
这样异或得到的区间数 w=O(n2log1018)w=O(n^2log10^{18})w=O(n2log1018),由于最后求所以区间交需要排序,所以总复杂度为 O(wlogw)O(wlogw)O(wlogw).
Code\text{Code}Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=105;
const int mod=998244353;
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
int na,nb;
ll o=(1ll<<60)-1;
#define mid ((l+r)>>1)
struct line{ll l,r;bool operator < (const line &o)const{return l<o.l;}
}a[N],b[N];
vector<line>va[80],vb[80];
void upd1(ll l,ll r,ll x,ll y,ll d){//printf(" upd1:(%lld %lld) (%lld %lld) d=%lld\n",l,r,x,y,d);va[d].push_back((line){l,r});if(x<=l&&r<=y) return;if(x<=mid) upd1(l,mid,x,y,d+1);if(y>mid) upd1(mid+1,r,x,y,d+1);return;
}
void upd2(ll l,ll r,ll x,ll y,ll d){//printf(" upd2:(%lld %lld) (%lld %lld) d=%lld\n",l,r,x,y,d);if(x<=l&&r<=y){vb[d].push_back((line){l,r});return;}if(x<=mid) upd2(l,mid,x,y,d+1);if(y>mid) upd2(mid+1,r,x,y,d+1);return;
}line ans[N*N*500];
int tot;
void solve(){for(int i=1;i<=na;i++) upd1(0,o,a[i].l,a[i].r,0);for(int i=1;i<=nb;i++) upd2(0,o,b[i].l,b[i].r,0);for(int d=1;d<=60;d++){for(auto u:va[d]){for(auto v:vb[d]){ll low=u.l^u.r;ans[++tot]=(line){(u.l^v.l)&(~low),(u.l^v.l)|low};//printf("(%lld %lld) ^ (%lld %lld) -> (%lld %lld)\n",u.l,u.r,v.l,v.r,ans[tot].l,ans[tot].r);}}}return;
}
ll res;
inline ll sum(ll a,ll b){a%=mod;b%=mod;return ((b-a+1)*(a+b)>>1)%mod;
}
signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifna=read();for(int i=1;i<=na;i++) a[i]=(line){read(),read()};nb=read();for(int i=1;i<=nb;i++) b[i]=(line){read(),read()};solve();for(int i=1;i<=60;i++) va[i].clear();//va[i].shrink_to_fit();for(int i=1;i<=60;i++) vb[i].clear();//vb[i].shrink_to_fit();swap(na,nb),swap(a,b);//printf("swap------\n");solve();sort(ans+1,ans+1+tot);ll l=ans[1].l,r=ans[1].r;//printf("(%lld %lld)\n",l,r);for(int i=2;i<=tot;i++){if(ans[i].l<=r) r=max(r,ans[i].r);else{(res+=mod+sum(l,r))%=mod;l=ans[i].l,r=ans[i].r;}//printf("(%lld %lld)\n",ans[i].l,ans[i].r);}(res+=mod+sum(l,r))%=mod;printf("%lld\n",res);return 0;
}
/*
*/