2021牛客OI赛前集训营-提高组(第二场)
vp 的,赛时 \(80+0+100+0\)
T1 不会,写了个分块+ST 表,发现常数还比暴力大。
T2 不会,看题解才会了,想到了经典套路之固定端点瞎选。
T3 萌萌数据结构,提示性挺强的,发现每个点都可以将 2 段序列合并成一段新的,考虑贪心即可,每次合并 2 段最大的序列,考虑 multiset+启发式合并
,优秀的 \(O(n\log^2n)\)。
T4 弃了。
赛后:
T1 发现交换没影响,因为如果 2 个位,考虑交换。
若原来贡献为 1,交换后也显然贡献为 1。
若原来贡献为 2,交换后贡献为 0。
若原来贡献为 0,交换后贡献为 2。
发现都对奇偶性没影响,考虑记录下区间 1 的数量即可。
T2
我们可以考虑固定一条线段看看能不能乱选。
考虑 2 个点 \(A(x,y),B(xx,yy)\)。
如何求出线段 \(AB\) 上的整点数量。
记 \(a=|x-xx|,b=|y-yy|\),答案显然是 \(\gcd(a,b)\),参考什么莫反的题。
把整一段拍扁到序列上,发现 \(D\) 的限制并不是很好做,但是考虑单位相隔长度一样,即每个点和它的横坐标加 1 的那个点的距离都是一样的。
令 \(dis=dist((0,0),(\dfrac{a}{\gcd(a,b)},\dfrac{b}{\gcd(a,b)}))\)
那么假如选了 0 和第 \(qwq\) 个点,合法当且仅当
令 \(qwq=\lceil\dfrac{D}{dis}\rceil\)
考虑只需要选 \(N-2\) 个点了,因为左右端点都选了。
那么答案为
\(-(qwq-1)*(N-1)\) 选 \(N\) 个点,间隔 \(N-1\),每个间隔至少 \(qwq-1\)。
最后考虑乘上答案系数,注意假如是不是水平/竖直线需要 \(\times2\),因为有序点对。
T1
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <set>
#include <bitset>
#include <cmath>
using namespace std;
int rd() {
char ch=getchar(); int sum=0,f=1;
while(ch>'9'||ch<'0') {
if(ch=='-') f=-1; ch=getchar();
}
while(ch<='9'&&ch>='0') sum=sum*10+ch-'0',ch=getchar();
return sum*f;
}
#define N (int)(2e5+3)
#define M 402
int n,m,Q;
bool gt() {
char ch=getchar();
while(ch!='0'&&ch!='1') ch=getchar();
return ch-'0';
}
struct BBB {
bitset<N>B[20][M];
int len,bl,id[N],L[M],R[M]; bool a[N];
void init(int lenn) {
len=lenn; bl=min(len,500);
for(int i=1;i<=len;i++) {
a[i]=gt(); id[i]=(i-1)/bl+1;
B[0][id[i]][i]=a[i];
}
for(int i=1;i<=id[len];i++) L[i]=(i-1)*bl+1,R[i]=i*bl; R[id[len]]=len;
for(int i=1;(1ll<<i)<=id[len];i++) {
for(int j=1;j+(1ll<<i)-1<=id[len];j++) {
B[i][j]=(B[i-1][j]|B[i-1][j+(1ll<<(i-1))]);
}
}
}
void get(int l,int r,bitset<N>&BT) {
// cout<<id[l]<<" "<<id[r]<<endl;
if(id[l]==id[r]) {
for(int i=l;i<=r;i++) {
if(a[i]) BT[i-l+1]=1;
}
} else {
// cout<<l<<" "<<R[id[l]]<<" "<<L[id[r]]<<" "<<r<<endl;
for(int i=l;i<=R[id[l]];i++) if(a[i]) BT[i-l+1]=1;
for(int i=L[id[r]];i<=r;i++) if(a[i]) BT[i-l+1]=1;
int x=id[l]+1,y=id[r]-1; if(x>y) return ;
int qwq=log2(y-x+1);
BT|=(B[qwq][x]>>(l-1)); BT|=(B[qwq][y-(1ll<<qwq)+1]>>(l-1));
}
}
}P1,P2;
bitset<N>r1,r2;
namespace xgf{
int a[N],b[N];
void solve() {
for(int i=1;i<=n;i++) a[i]=gt();
for(int i=1;i<=m;i++) b[i]=gt();
Q=rd();
int l,r,ll,rr;
while(Q--) {
l=rd(); r=rd(); ll=rd(); rr=rd(); int qwq=0;
for(int i=0;i<r-l+1;i++) if(a[l+i]!=b[ll+i]) ++qwq;
if(qwq&1) puts("1"); else puts("0");
}
}
}
int main() {
// freopen("string2.in","r",stdin); freopen("qwq.out","w",stdout);
n=rd(); m=rd();
if(n<=(int)(5e4)) {
xgf::solve(); return 0;
}
P1.init(n); P2.init(m);// P1.DE();
Q=rd(); int l,r,ll,rr;
while(Q--) {
l=rd(); r=rd(); ll=rd(); rr=rd();
r1.reset(); r2.reset(); P1.get(l,r,r1); P2.get(ll,rr,r2);
/* for(int i=0;i<r-l+1;i++) cout<<r1[i]; puts("");
for(int i=0;i<r-l+1;i++) cout<<r2[i]; puts("");
*/
int qwq=(r1^r2).count(); //cout<<qwq<<endl;
if(qwq&1) puts("1"); else puts("0");
}
return 0;
}
T2
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <set>
#include <bitset>
#include <cmath>
#define ll long long
#define mod (int)(1e9+7)
using namespace std;
int rd() {
char ch=getchar(); int sum=0,f=1;
while(ch>'9'||ch<'0') {
if(ch=='-') f=-1; ch=getchar();
}
while(ch<='9'&&ch>='0') sum=sum*10+ch-'0',ch=getchar();
return sum*f;
}
ll lrd() {
char ch=getchar(); ll sum=0,f=1;
while(ch>'9'||ch<'0') {
if(ch=='-') f=-1; ch=getchar();
}
while(ch<='9'&&ch>='0') sum=sum*10+ch-'0',ch=getchar();
return sum*f;
}
ll C[2003][2003];
ll N,W,H,D;
ll fpow(ll x,ll y) {
ll res=1; x%=mod;
while(y) {
if(y&1) res=res*x%mod; y>>=1; x=x*x%mod;
}
return res;
}
ll gcd(ll x,ll y) {
return !y?x:gcd(y,x%y);
}
double dis(ll x,ll y,ll xx,ll yy) {
return sqrt(1.0*(x-xx)*(x-xx)+1.0*(y-yy)*(y-yy));
}
ll CC(ll x,ll y) {
if(x<y||y<0) return 0;
return C[x][y];
}
ll work(ll x,ll y) {
if(x==0&&y==0) return 0;
ll d=gcd(x,y);
ll k=ceil(D/dis(0,0,x/d,y/d));
int qwq=CC(d-1-(N-1)*(k-1),N-2);
if(x!=0&&y!=0) qwq=qwq*2ll%mod; // (x1,y1) (x2,y2) 倒过来
return qwq;
}
void solve() {
N=lrd(); W=lrd(); H=lrd(); D=lrd(); ll ans=0;
if(N==1) {
printf("%lld\n",(W+1)*(H+1)); return ;
}
for(int i=0;i<=W;i++) {
for(int j=0;j<=H;j++) ans=(ans+(W-i+1)*(H-j+1)%mod*work(i,j)%mod)%mod;
}
ans=(ans%mod+mod)%mod;
printf("%lld\n",ans);
}
int main() {
C[0][0]=1;
for(int i=1;i<=2000;i++) {
C[i][0]=1; for(int j=1;j<=i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
int T=rd(); while(T--) solve(); return 0;
}
T3
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <set>
using namespace std;
int rd() {
char ch=getchar(); int sum=0,f=1;
while(ch>'9'||ch<'0') {
if(ch=='-') f=-1; ch=getchar();
}
while(ch<='9'&&ch>='0') sum=sum*10+ch-'0',ch=getchar();
return sum*f;
}
#define N (int)(1e5+5)
struct edge {
int nex,to;
}e[N<<1];
multiset<int,greater<int> >s[N];
multiset<int>::iterator it;
int head[N],cnt,id[N],n;
void add_edge(int x,int y) {
e[++cnt].nex=head[x]; e[cnt].to=y; head[x]=cnt;
}
void dfs1(int x,int ff) {
for(int i=head[x];i;i=e[i].nex) {
int y=e[i].to; if(y==ff) continue;
dfs1(y,x);
if(s[id[y]].size()>s[id[x]].size()) swap(id[x],id[y]);
for(it=s[id[y]].begin();it!=s[id[y]].end();it++) s[id[x]].insert(*it);
s[id[y]].clear();
}
if(!s[id[x]].size()) s[id[x]].insert(1);
else if(s[id[x]].size()==1) {
it=s[id[x]].begin(); s[id[x]].insert(*it+1); s[id[x]].erase(it);
} else {
int qwq=1; it=s[id[x]].begin(); qwq+=*it; s[id[x]].erase(it); it=s[id[x]].begin(); qwq+=*it; s[id[x]].erase(it);
s[id[x]].insert(qwq);
}
}
void solve() {
n=rd(); cnt=0; memset(head,0,sizeof(head));
for(int i=1;i<=n;i++) {
id[i]=i; s[i].clear();
}
int x,y;
for(int i=1;i<n;i++) x=rd(),y=rd(),add_edge(x,y),add_edge(y,x);
dfs1(1,0); printf("%d\n",*s[id[1]].begin());
}
int main() {
//freopen("qwq.out","w",stdout);
int T=rd(); while(T--) solve(); return 0;
}