1. 程式人生 > 其它 >noip模擬38(待補)

noip模擬38(待補)

A. a

顯然本題應該是\(n*m\)做法,然而我帶了個樹狀陣列的\(log\),卡了卡過了..

正解應該是列舉左上端點,然後考慮維護兩個單調指標..
我們發現隨著右下端點高度的下移,那麼\(l\)\(r\)作為邊界的指標也會單調向左移動..
於是\(O(n*m)\)便可做了..

A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define ll int 
	#define ull unsigend ll
	#define re register ll 
	#define lf double
	#define lbt(x) (x&(-x))
	#define mp(x,y) make_pair(x,y)
	#define lb lower_bound 
	#define ub upper_bound
	#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
	#define Fill(x,y) memset(x,y,sizeof x)
	#define Copy(x,y) memset(x,y,sizeof x)
	inline ll read() {
		ll ss=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0; 
		while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
		return cit?ss:-ss;
	}
} using namespace BSS;

const ll N=35,M=5e4+51;
ll m,n,l,r,flag;
long long int ans;
char s[M];
ll c[N*M],f[N*M];
ll g[N][M],pre[N][M],sum[M*N];
inline ll query(ll x){
	ll res=0;
	if(x<0) return 0;
	while(x) res+=c[x],x-=lbt(x);
	return res+c[0];
}
inline void update(ll x,ll num){
	if(x==0) c[x]+=num;
	else while(x<=pre[n][m]+2) c[x]+=num,x+=lbt(x);
	return ;
}
signed main(){
	n=read(),m=read();
	flag=1;
	for(re i=1;i<=n;++i){
		scanf("%s",s+1);
		for(re j=1;j<=m;++j)
			pre[i][j]=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+s[j]-'0',
			flag&=(s[j]=='1');
	}
	l=read(),r=read();
	if(flag){
		for(re i=1;i<=n;i++){
			for(re j=1;j<=m;j++){
				if(i*j>r) break;
				if(i*j>=l and i*j<=r) ans+=1ll*(n-i+1)*(m-j+1);
			}
		}
		printf("%lld",ans);
		return 0;
	}
    if(l==0 and r==n*m){  
		for(re i=1;i<=n;i++)
			for(re j=1;j<=m;j++)
					ans+=1ll*(n-i+1)*(m-j+1);
		printf("%lld",ans);
		return 0;
	}
	ll temp,cnt;
	for(re i=0;i<=n;++i){
		for(re j=i+1;j<=n;++j){
			cnt=0;
			for(re k=0;k<=m;++k){
				temp=pre[j][k]-pre[i][k],
				ans+=query(temp-l)-query(temp-r-1);
				update(temp,1); 
			}
			for(re k=0;k<=pre[n][m];++k) c[k]=0;
		}
	}
	printf("%lld",ans);
	return 0;
}

B. b

考場上考慮了一個維護每個質因子的貢獻,然而事實上並不單單是質因子..
維護每個因子的貢獻,發現會有重複,於是簡單的容斥原理減去即可.

B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define ll long long int 
	#define ull unsigend ll
	#define re register ll 
	#define lf double
	#define mp(x,y) make_pair(x,y)
	#define lb lower_bound 
	#define ub upper_bound
	#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
	#define Fill(x,y) memset(x,y,sizeof x)
	#define Copy(x,y) memset(x,y,sizeof x)
	inline ll read() {
		ll ss=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0; 
		while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
		return cit?ss:-ss;
	}
} using namespace BSS;
 
const ll N=25,M=1e5+51;
const ll mod=1e9+7; 
ll n,m,maxn,res;
ll ans[M];
ll val[N][M],cnt[N][M],bkt[N][M];
signed main(){
	n=read(); m=read();
	ll temp=0;
	for(re i=1;i<=n;i++)
		for(re j=1;j<=m;j++)
			temp=read(),maxn=max(maxn,temp),bkt[i][temp]++;
	for(re i=1;i<=n;i++){
		for(re j=1;j<=maxn;j++)
			for(re k=1;k*j<=maxn;k++)
				(cnt[i][j]+=bkt[i][k*j])%mod;
	}
/*	for(re i=1;i<=n;i++){
		for(re j=1;j<=maxn;j++) 
			cout<<cnt[i][j]<<" ";
		cout<<'\n';
	}
*/	for(re i=maxn;i>=1;i--){
		ans[i]=1;		
		for(re j=1;j<=n;j++) ans[i]=(ans[i]*(cnt[j][i]+1))%mod;
		--ans[i];
		for(re j=2;j*i<=maxn;j++) ans[i]=(ans[i]-ans[j*i]+mod)%mod;
		(res+=ans[i]*i)%=mod;
	}	
	printf("%lld",res);
	return 0;
}

C.c

點分治.