A. Equivalent Prefixes
--两个单调栈维护
#include<bits/stdc++.h> using namespace std; const int maxn=5e5+10; int a[maxn],b[maxn]; int dp1[maxn],dp2[maxn]; int main() { int n; while( ~scanf("%d",&n) ) { for( int i=1;i<=n;i++ ) scanf("%d",&a[i]); for( int i=1;i<=n;i++ ) scanf("%d",&b[i]); stack<int>p,q; int ans=1; for( int i=1;i<=n;i++ ) { if( p.empty() ) { dp1[i]=i; p.push(i); } else { while( !p.empty() && a[p.top()]>a[i] ) p.pop(); if(!p.empty() ) dp1[i]=p.top(); else dp1[i]=i; p.push(i); } if( q.empty() ) { dp2[i]=i; q.push(i); } else { while( !q.empty() && b[q.top()]>b[i] ) q.pop(); if(!q.empty() ) dp2[i]=q.top(); else dp2[i]=i; q.push(i); } if( dp1[i]==dp2[i] ) ans=i; else break; } printf("%d\n",ans); } }
E. ABBA
待补
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2e3+5; const int mod=1e9+7; ll dp[maxn][maxn]; int main() { int n,m; while( ~scanf("%d%d",&n,&m) ) { for( int i=0;i<=n+m;i++ ) { for( int j=0;j<=n+m;j++ ) dp[i][j]=0; } dp[0][0]=1; for( int i=0;i<=n+m;i++ ) { for( int j=0;j<=n+m;j++ ) { if( i-j<=n && i>0 ) dp[i][j]=(dp[i][j]+dp[i-1][j])%mod; if( j-i<=m && j>0 ) dp[i][j]=(dp[i][j]+dp[i][j-1])%mod; } } printf("%lld\n",dp[n+m][n+m]); } }
F. Random Point in Triangle
手推结论或者随机数找规律 (待补找规律过程)
#include<bits/stdc++.h> #define ll long long using namespace std; int main() { ll a,b,c,d,e,f; while( ~scanf("%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&e,&f) ) { printf("%lld\n",1ll*abs(a*d+c*f+e*b-c*b-e*d-a*f)*11); } return 0; }
H. XOR
很明显是一题线性基的题目
题意:给定n个整数,求满足子集异或和为0的子集大小之和。
题解:相当于求每个数出现在子集中的次数之和。
先对n个数求线性基,设线性基大小为r,可以分别计算线性基内数的贡献和线性基外数的贡献
1.线性基外:共n-r个数,枚举每个数x,将线性基外剩余的n-r-1个数任意排列,显然共有 。
2.线性基内:枚举每个数x,将所有剩余的n-1个数再求一次线性基,设为B,分两种情况:
(1).x不能被B异或出。那么显然x不能在任意一个集合中出现,x的贡献为0。
(2).x可以被B异或出。此时B的大小必定也为r,因为B已经能表示所有n个数了。那么在除去x和B的情况下,剩余n-r-1个数显然也是任意排列,x贡献为 。
#include<bits/stdc++.h> using namespace std; // 求每个数出现在子集的次数之和 // 先对n个数求线性基,设线性基大小为 r,可以分别计算线性基内数的贡献和线性基外数的贡献 typedef long long ll; const int maxn=1e5+10; const int mod=1e9+7; int n,k; struct Linear_Basis { static const int wei=63; ll p[wei],np[wei],r; void init() { r=0; memset(p,0,sizeof(p)); memset(np,0,sizeof(np)); } bool ins( ll x ) { for( int i=wei-1;i>=0;i-- ) { if( x>>i & 1 ) { if( p[i] ) x^=p[i]; else { ++r; p[i]=x; break; } if( !x ) break; } } return x>0 ; // 线性无关 or 线性相关 } }LB,L; ll a; vector<ll> vec; ll qpow( ll x,ll y ) { ll ans=1; while( y ) { if( y&1 ) ans=ans*x%mod; y>>=1; x=x*x%mod; } return ans; } int main() { while( ~scanf("%d",&n) ) { LB.init();L.init(); vec.clear(); for( int i=1;i<=n;i++ ) { scanf("%lld",&a); if( LB.ins(a) ) vec.push_back(a); else L.ins(a); } ll ans=qpow(2,n-LB.r-1)*(n-LB.r)%mod; // 线性基外 for( int i=0;i<vec.size();i++ ) { Linear_Basis tp(L); for( int j=0;j<vec.size();j++ ) { if( i!=j ) tp.ins(vec[j]); } if( tp.r==LB.r ) ans=(ans+qpow(2,n-LB.r-1))%mod; // n个数生成的不同线性基个数相等,所以只需判断线性基个数是否相同, // 就可以判断a[i]是否能放进去 } printf("%lld\n",ans); } }
I. Points Division
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=1e5+10; struct node{ int x,y,a,b; }p[maxn]; int n,m,num[maxn],tot; struct ST { #define ls i << 1 #define rs i << 1 | 1 struct node { ll max, lazy; int l, r; } T[maxn<< 2]; inline void push_up(int i) { T[i].max = max(T[ls].max, T[rs].max); } void build(int i, int l, int r) { T[i] = node{0, 0, l, r}; if (l == r) { T[i].max = -inf; T[i].lazy = 0; return; } int mid = (l + r) >> 1; build(ls, l, mid); build(rs, mid + 1, r); push_up(i); } inline void push_down(int i) { T[ls].lazy += T[i].lazy; T[rs].lazy += T[i].lazy; T[ls].max += T[i].lazy; T[rs].max += T[i].lazy; T[i].lazy = 0; } void update(int i, int l, int r, ll x) { if (l > r) return; if ((T[i].l == l) && (T[i].r == r)) { T[i].lazy += x; T[i].max += x; return; } if (T[i].lazy != 0) push_down(i); int mid = (T[i].l + T[i].r) >> 1; if (mid >= r) update(ls, l, r, x); else if (mid < l) update(rs, l, r, x); else { update(ls, l, mid, x); update(rs, mid + 1, r, x); } push_up(i); } void upd(int i, int pos, ll x) { if (T[i].l == T[i].r) { T[i].max = max(T[i].max, x); return; } if (T[i].lazy != 0) push_down(i); int mid = (T[i].l + T[i].r) >> 1; if (mid >= pos) upd(ls, pos, x); else upd(rs, pos, x); push_up(i); } ll getmax(int i, int l, int r) { if (l > r) return 0; if ((T[i].l == l) && (T[i].r == r)) return T[i].max; if (T[i].lazy != 0) push_down(i); int mid = (T[i].l + T[i].r) >> 1; if (mid >= r) return getmax(ls, l, r); else if (mid < l) return getmax(rs, l, r); else return max(getmax(ls, l, mid), getmax(rs, mid + 1, r)); } } seg; inline bool cmp(node a, node b) { return a.x == b.x ? a.y > b.y : a.x < b.x; } int main() { while( ~scanf("%d",&n) ) { tot=0; for( int i=1;i<=n;i++ ) { scanf("%d%d%d%d",&p[i].x,&p[i].y,&p[i].a,&p[i].b); num[++tot]=p[i].y; } sort(num+1,num+1+tot); tot=unique(num+1,num+1+tot)-num-1; for( int i=1;i<=n;i++ ) { p[i].y=lower_bound(num+1,num+1+tot,p[i].y)-num+1; } tot++; sort(p+1,p+1+n,cmp); seg.build(1,1,tot); seg.upd(1,1,0); for( int i=1;i<=n;i++ ) { ll cur=seg.getmax(1,1,p[i].y); seg.upd(1,p[i].y,cur+p[i].b); //单点更新 seg.update(1, p[i].y + 1, tot, p[i].b); // 区间更新 seg.update(1, 1, p[i].y - 1, p[i].a); } printf("%lld\n", seg.T[1].max); } return 0; }
J.Fraction Comparision
#include<bits/stdc++.h> #define ll long long using namespace std; int main() { ll x,a,y,b; while( ~scanf("%lld %lld %lld %lld",&x,&a,&y,&b) ) { if( x*b==y*a )puts("="); else puts( x/a==y/b?( ( (x%a)*b>(y%b)*a )?">":"<") : (x/a>y/b?">":"<") ); } }