C
树的性质是点-边=1
森林联通块计数都可以这么做所以直接维护前缀和再把边界处理一下就好了
//Love and Freedom. #include<algorithm> #include<cstring> #include<cmath> #include<cstdio> #define inf 20021225 #define ll long long #define N 2100 using namespace std; int read() { int f=1,s=0; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return f*s; } int a[N][N],p[N][N],e[N][N],hp[N][N],lp[N][N],n,m; char ch[N]; int main() { n=read(),m=read(); int Q=read(); for(int i=1;i<=n;i++) { scanf("%s",ch+1); for(int j=1;j<=m;j++) { a[i][j]=ch[j]-'0'; p[i][j]=p[i-1][j]+p[i][j-1]-p[i-1][j-1]+a[i][j]; e[i][j]=e[i-1][j]+e[i][j-1]-e[i-1][j-1]+(a[i][j]&a[i-1][j])+(a[i][j-1]&a[i][j]); hp[i][j]=hp[i][j-1]+(a[i][j]&a[i-1][j]); lp[i][j]=lp[i-1][j]+(a[i][j]&a[i][j-1]); } } while(Q--) { int h1=read(),l1=read(),h2=read(),l2=read(); int poi=p[h2][l2]-p[h2][l1-1]-p[h1-1][l2]+p[h1-1][l1-1]; //printf("%d %d %d %d ",p[h2][l2],p[h2][l1-1],p[h1-1][l2],p[h1-1][l1-1]); int ed=e[h2][l2]-e[h2][l1-1]-e[h1-1][l2]+e[h1-1][l1-1]; //printf("%d ",ed); ed -= hp[h1][l2]-hp[h1][l1-1]; ed -= lp[h2][l1]-lp[h1-1][l1]; //printf("%d %d %d %d ",hp[h1][l2],hp[h1][l1-1],lp[h2][l1],lp[h1-1][l1]); printf("%d ",poi-ed); } return 0; }
D
神仙思路题(我没脑子)
考虑首先AB的最长公共前缀一定可以丢掉
然后下一位B是1A是0
我么设这一位为p
考虑[A,1<<p)的答案和[1<<p,B]的答案
显然只取前面一个集合的答案就是(1<<p)-A
只取后面的 我们考虑B接下来最高位的一个1 记为k
那么答案就是[1<<p,(1<<p) + (1<<k+1) -1]
最后考虑两个都取 答案是[(1<<p)+A,(2<<p)-1]
发现后面两个需要取并
这类题的思路主要在于取值是区间因此答案也是区间
//Love and Freedom. #include<algorithm> #include<cstring> #include<cmath> #include<cstdio> #define inf 20021225 #define ll long long using namespace std; int read() { int f=1,s=0; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return f*s; } int main() { ll a,b; scanf("%lld%lld",&a,&b); ll ans=0; if(a==b) return puts("1"),0; for(int i=60;~i;i--) if((a>>i&1)!=(b>>i&1)) { a&=(1ll<<i+1)-1; b&=(1ll<<i)-1; ll p=1ll<<i; ans+=p-a; for(;~i;i--) if(b>>i&1) break; i++; ans+=1ll<<i; a=max(1ll<<i,a); //printf("%lld %lld %lld ",ans,i,a); ans+=p-a; break; } printf("%lld ",ans); return 0; }
E
其实就差一步了(枯了
考虑一个点能染的点
有显然的两种
1.xj<xi vj>vj
2.xj>xi vj<vi
我们继续考虑一些复杂的
发现对于位置位于当前点之前的速度最大的点若比它的速度大的话就一定会把所有速度小于这个最大值的所有点染色(想想为什么?)
后面的同理
所以按照速度排序以后变成了区间覆盖的方案数
显然可以线段树优化(哦其实可以直接前缀和优化 可惜我懒qwq)
所以就做完了
//Love and Freedom. #include<algorithm> #include<cstring> #include<cmath> #include<cstdio> #define inf 20021225 #define ll long long #define N 200100 #define mdn 1000000007 #define ls (x<<1) #define rs (x<<1|1) #define mid (l+r>>1) using namespace std; int read() { int f=1,s=0; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return f*s; } void upd(int &x,int y){x+=x+y>=mdn?y-mdn:y;} int t[N<<2]; void pushup(int x){t[x]=(t[ls]+t[rs])%mdn;} void modify(int x,int l,int r,int d,int val) { if(l==r){upd(t[x],val); return;} if(d<=mid) modify(ls,l,mid,d,val); else modify(rs,mid+1,r,d,val); pushup(x); } int query(int x,int l,int r,int LL,int RR) { if(LL<=l&&RR>=r) return t[x]; int ans=0; if(LL<=mid) upd(ans,query(ls,l,mid,LL,RR)); if(RR>mid) upd(ans,query(rs,mid+1,r,LL,RR)); return ans; } struct node{int x,v,idx,idv;}a[N]; struct seg{int l,r;}s[N]; bool operator<(seg a,seg b){return a.r<b.r||(a.r==b.r&&a.l<b.l);} bool cmpv(node x,node y){return x.v<y.v;} bool cmpx(node x,node y){return x.x<y.x;} int pre[N],suf[N],n,v[N]; int main() { n=read(); for(int i=1;i<=n;i++) a[i].x=read(),a[i].v=read(); sort(a+1,a+n+1,cmpv); for(int i=1;i<=n;i++) a[i].idv=i,v[i]=a[i].v; sort(a+1,a+n+1,cmpx); //suf[n+1]=inf*99; for(int i=1;i<=n;i++) { if(i==1) pre[1]=a[1].idv; else { if(a[i].v>v[pre[i-1]]) pre[i]=a[i].idv; else pre[i]=pre[i-1]; } a[i].idx=i; } for(int i=n;i;i--) { if(i==n) suf[n]=a[n].idv; else { if(a[i].v<v[suf[i+1]]) suf[i]=a[i].idv; else suf[i]=suf[i+1]; } } modify(1,0,n,0,1); for(int i=1;i<=n;i++) { int r=pre[a[i].idx],l=suf[a[i].idx]; s[i].l=l; s[i].r=r; } sort(s+1,s+n+1); for(int i=1;i<=n;i++) { int l=s[i].l,r=s[i].r; int val=query(1,0,n,l-1,r); modify(1,0,n,r,val); } printf("%d ",query(1,0,n,n,n)); return 0; }
F
第一问显然是Fib(昨天刚好学类欧于是反应贼快)
第二问还8会 等我咕会
我去世了 下一周 我们就考到了这个题/px
具体做法很神仙 我懒得写了 大概就是考虑递推出来的组数都不会特别多
然后考虑再从上一层推出当前答案即可
//Love and Freedom. #include<algorithm> #include<cstring> #include<cmath> #include<cstdio> #include<vector> #define inf 20021225 #define ll long long #define pa pair<ll,ll> #define mp make_pair #define pb push_back #define mdn 1000000007 using namespace std; int read() { int f=1,s=0; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return f*s; } ll fib[100]; vector<pa> ans[100]; int work(ll a,ll b,ll x,ll y) { int cur=0; if(x>=b&&y>=a+b) (cur+=(y-a)/b%mdn)%mdn; if(y>=b&&x>=a+b) (cur+=(x-a)/b%mdn)%mdn; return cur; } int main() { int top; fib[0]=fib[top=1]=1; while(fib[top]<=4e18) ++top,fib[top]=fib[top-1]+fib[top-2]; ans[0].pb(mp(0ll,1ll)),ans[0].pb(mp(0ll,2ll)); for(int i=0;i+3<=top;i++) { for(int j=0;j<ans[i].size();j++) { ll x=ans[i][j].first,y=ans[i][j].second; x+=y; while(x<=fib[i+3]+fib[i]) { if(x>y) ans[i+1].pb(mp(y,x)); x+=y; } } } int q=read(); while(q--) { ll x,y; scanf("%lld%lld",&x,&y); if(x>y) swap(x,y); int cur=1; while(fib[cur+2]<=y&&fib[cur+1]<=x) cur++; printf("%d ",cur); int sum=0; if(cur==1){printf("%lld ",x%mdn*y%mdn); continue;} for(int i=0;i<ans[cur-1].size();i++) (sum+=work(ans[cur-1][i].first,ans[cur-1][i].second,x,y))%=mdn; printf("%d ",sum); } return 0; }