【省選模擬】20/02/29

「2017 山東一輪集訓 Day1」Sum

  • dpi,jdp_{i,j} 表示和爲 ii 模爲 jj 的個數,p2p^2 枚舉 jjii 是一個卷積,於是就可以快速冪了
    複雜度 O(mlog(n)log(m)p+mp2log(n))O(mlog(n)log(m)p+mp^2log(n))
#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
void Add(int &a, int b){ a = add(a, b); }
void Dec(int &a, int b){ a = dec(a, b); }
void Mul(int &a, int b){ a = mul(a, b); }
int ksm(int a, int b){ int as=1; for(;b;b>>=1,a=mul(a,a)) if(b&1) as=mul(as,a); return as; }
#define poly vector<int>
#define pb push_back
cs int M = 60;
int n, p, m;
cs int K = 12;
poly w[K+1]; 
int bit, up, Iv; poly rev;
void Rev_init(int deg){
	bit=0; up=1; while(up<deg) up<<=1,++bit; rev.resize(up); Iv=ksm(up,Mod-2);
	for(int i=0;i<up;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
}
void NTT_init(){
	for(int i=1; i<=K; i++) w[i].resize(1<<(i-1));
	int wn=ksm(3,(Mod-1)/(1<<K)); w[K][0]=1;
	for(int i=1; i<(1<<(K-1)); i++) w[K][i]=mul(w[K][i-1],wn);
	for(int i=K-1;i;i--) for(int j=0;j<(1<<(i-1));j++) w[i][j]=w[i+1][j<<1];
}
struct atom{
	poly a[M];
	void init_zero(){ a[0][0]=1; }
	void init_one(){ for(int i=0;i<min(10,m+1);i++) ++a[i%p][i]; }
	atom(){ for(int i=0;i<p;i++) a[i].clear(),a[i].resize(m+1); }
	int val(int x){ return a[0][x]; }
};
void NTT(poly &a, int typ){
	for(int i=0; i<up; i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
	for(int i=1,l=1; i<up; i<<=1,++l)
	for(int j=0; j<up; j+=(i<<1))
	for(int k=0; k<i; k++){
		int x=a[k+j], y=mul(w[l][k],a[k+j+i]);
		a[k+j]=add(x,y); a[k+j+i]=dec(x,y);
	}
	if(typ==-1){
		reverse(a.begin()+1,a.end());
		for(int i=0;i<up;i++) Mul(a[i],Iv);
	}
}
void output(poly a){ for(int i=0; i<a.size();i++)cout<<a[i]<<" "; puts(""); }
void NTT_trans(poly &a, int typ){ a.resize(up); NTT(a,typ); if(typ==-1) a.resize(m+1); }
void inc(poly &a, poly b){ a.resize(b.size()); for(int i=0; i<(int)a.size(); i++) Add(a[i],b[i]); }
poly dot(poly a, poly b){ for(int i=0; i<(int)a.size(); i++) Mul(a[i],b[i]); return a; }
atom Mul(atom A, atom B, int deg){
	for(int i=0; i<p; i++) NTT_trans(A.a[i],1);
	for(int i=0; i<p; i++) NTT_trans(B.a[i],1);
	atom C;
	for(int i=0; i<p; i++)
	for(int j=0; j<p; j++) 
	inc(C.a[(i*deg+j)%p],dot(A.a[i],B.a[j]));
	for(int i=0; i<p; i++) NTT_trans(C.a[i],-1);
	return C;
}
int main(){
	freopen("sum.in","r",stdin);
	freopen("sum.out","w",stdout);
	cin >> n >> p >> m; NTT_init(); Rev_init(m+1+m);
	atom A, B; A.init_one(); B.init_zero(); 
	static int pw[M]; pw[0]=1; pw[1]=10;
	for(int i=2; i<=32; i++) pw[i]=pw[i-1]*pw[i-1]%p; int deg=1;
	for(int i=0;n;i++,n>>=1){
		if(n&1){ B=Mul(A,B,deg); deg=deg*pw[i+1]%p; } 
		A=Mul(A,A,pw[i+1]);
	}
	for(int i=0,as=0;i<=m;i++){
		Add(as,B.val(i)); cout<<as<<" ";
	} return 0;
}

「2017 山東一輪集訓 Day1 」Set

  • 考慮 x1x2=xx_1\otimes x_2=x 是一個定值,於是貪心,當前位爲 0 拆成兩個 1,當前位爲 1 拆成一個 1 一個 0,然後我的一個非常 naivenaive 得想,如果當前位爲 1 那麼我們貪心把 x1x_1 搞成 0,但這樣做是不對的,這樣只保證了 x1x_1 最小沒有保證 x1+x2x_1+x_2 最大
  • 正解挺巧妙的,首先對爲 0 的位貪心,放最多的 1,然後在這個基礎上把不爲 0 的位搞儘量多的 1,
    把不爲 0 的位搞儘量多的 1不能影響爲 0 位放的 1,所以我們改變一下插入的線性基的順序,把爲 0 的位置的數消去就不會影響了
#include<bits/stdc++.h>
#define cs const
using namespace std;
typedef long long ll;
template <typename T> T read(){
	T cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
	while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
	return cnt * f;
} 
int gi(){ return read<int>(); }
ll gl(){ return read<ll>(); }
cs int N = 1e5 + 50;
ll A[70], x[N], Xor; int n;
void ins(ll x){
	for(int i = 60; ~i; i--) if(!(Xor >> i & 1)){
		if(x >> i & 1){
			if(A[i]) x ^= A[i];
			else{ A[i] = x; return; }
		}
	}
	for(int i = 60; ~i; i--) if(Xor >> i & 1){
		if(x >> i & 1){
			if(A[i]) x ^= A[i];
			else{ A[i] = x; return; }
		}
	}
}
int main(){
	n = gi();
	for(int i = 1; i <= n; i++) 
		x[i] = gl(), Xor ^= x[i];
	for(int i = 1; i <= n; i++) ins(x[i]);
	ll v = 0;
	for(int i = 60; i >= 0; i--) if(!(Xor >> i & 1) && !(v >> i & 1)) v ^= A[i];
	for(int i = 60; i >= 0; i--) if((Xor >> i & 1) && (v >> i & 1)) v ^= A[i];
	cout << v; return 0;  
}

「2017 山東一輪集訓 Day2」Pair

  • 考慮 hallhall 定理,AA 中任意 kk 個要匹配 BB 中至少 kk 個,那麼我們先預處理每個數可以匹配幾個,計爲 aia_i,那麼合法的一個區間需要滿足 i,airanki\forall i,a_i\ge rank_i
    所以我們可以用線段樹動態維護一個排名,考慮插入或刪除一個對後面的貢獻就可以了
#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int N = 2e5 + 50;
cs int INF = 1e9 + 7;
template <typename T> T read(){
	T cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
	while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
	return cnt * f;
} 
int gi(){ return read<int>(); }
int n, m, H, a[N], b[N];
namespace SGT{
	cs int N = ::N << 2;
	int mn[N], tag[N], sz[N];
	#define mid ((l+r)>>1) 
	void build(int x, int l, int r){ 
		mn[x] = INF; if(l == r) return;
		build(x<<1,l,mid); build(x<<1|1,mid+1,r);
	}
	void pushup(int x){
		sz[x]=sz[x<<1]+sz[x<<1|1];
		mn[x]=min(mn[x<<1],mn[x<<1|1]);
	}
	void puttag(int x, int v){ mn[x]+=v; tag[x]+=v; }
	void down(int x){ if(tag[x]) puttag(x<<1,tag[x]),puttag(x<<1|1,tag[x]),tag[x]=0; }
	void ins(int x, int l, int r, int p, int v){ 
		if(l==r){ 
			if(~v) ++sz[x], mn[x]=l-v; 
			else{ --sz[x]; if(sz[x]==0) mn[x]=INF; }
			return;
		} down(x);
		(p<=mid)?ins(x<<1,l,mid,p,v):ins(x<<1|1,mid+1,r,p,v);
		pushup(x);
	}
	void modify(int x, int l, int r, int L, int R, int v){
		if(L<=l&&r<=R){ puttag(x,v); return; } down(x);
		if(L<=mid) modify(x<<1,l,mid,L,R,v);
		if(R>mid) modify(x<<1|1,mid+1,r,L,R,v); pushup(x);
	}
	int query(int x, int l, int r, int L, int R){
		if(L<=l&&r<=R) return sz[x]; int as=0;
		if(L<=mid) as+=query(x<<1,l,mid,L,R);
		if(R>mid) as+=query(x<<1|1,mid+1,r,L,R); return as;
	}
}
int main(){
	n = gi(), m = gi(), H = gi();
	for(int i = 1; i <= m; i++) b[i] = gi();
	sort(b+1, b+m+1);
	for(int i = 1; i <= n; i++){
		int x = gi(); 
		a[i] = lower_bound(b+1, b+m+1, H-x) - b - 1;
		a[i] = m - a[i];
	}
	int as = 0; SGT::build(1,0,m);
	for(int i = 1; i <= n; i++){
		int rk = SGT::query(1,0,m,0,a[i]);
		SGT::ins(1,0,m,a[i],rk);
		SGT::modify(1,0,m,a[i],m,-1);
		if(i>m){
			SGT::modify(1,0,m,a[i-m],m,1);
			SGT::ins(1,0,m,a[i-m],-1);
		}
		if(i>=m && SGT::mn[1]>=0) ++as;
	} cout << as; return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章