高一小学期2

A.同类分布

本来看着挺像月之迷的(其实就是一模一样),但是鉴于我自己不是非常会打月之迷(其实应该自信点的,虽然当时是贺的题解但是大体思路还是会的),而且数据范围只有 \(2^{31}\),所以就去分块打表了.

赛时爆搜

#include<bits/stdc++.h>
using namespace std;
const int N=100000;
//int f[11][91][N+1];
#define int long long
int a,b;
int dfs(int pos,int digsum,int num,int r,bool limit){
//	if(r<=N and f[pos][digsum][num]) return f[pos][digsum][num];
//	cout<<pos<<" "<<digsum<<" "<<num<<" "<<r<<endl;
//	if(pos>r/10+1) return 0;
	int ans=0;
	for(int i=limit;i<=9;++i){
		if(num*10+i<=r){
			ans+=dfs(pos+1,digsum+i,num*10+i,r,false);
		}
		else break;
	}
	if(digsum and num%digsum==0) ans++;
	return ans;
//	if(r<=N) return ans;
//	return f[pos][digsum][num]=ans;
}
int sol(int r){
//	memset(f,0,sizeof f);
	return dfs(0,0,0,r,true);
}
signed main(){
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
//	freopen("a.in","r",stdin);
//	freopen("out.out","w",stdout);
	cin>>a>>b;
	cout<<sol(b)-sol(a-1);
}

赛时分块打表

#include<bits/stdc++.h>
using namespace std;
#define int long long
int ans[]={
806095,1581855,2329984,3052160,3750525,4427492,5084970,5724686,6347468,6954793,
7732131,8481543,9205050,9904095,10581019,11237788,11875940,12497616,13103432,
13694682,14446019,15171368,15872614,16550673,17207734,17845948,18466778,19072027,19662166,
20238658,20966010,21669203,22349898,23008770,23647763,24268780,24873479,25463707,26039575,
26602369,27307487,27990025,28651439,29292198,29914298,30519347,31108837,31684643,32246926,
32796782,33480907,34144108,34787529,35411317,36017597,36607817,37183292,37745713,38295232,
38832914,39497335,40142121,40768651,41376852,41968476,42544806,43107279,43657184,44194636,
44720629,45366844,45994799,46605449,47198975,47777248,48340949,48891281,49429749,49956416,
50471934,51099607,51710497,52305518,52884417,53449198,54000471,54539065,55066115,55581915,
56087100,56697604,57292496,57872728,58438097,58990253,59529673,60057199,60573660,61079255,
61574510,62350092,63097869,63819541,64518767,65196025,65853422,66492929,67115939,67723180,
68315858,69065001,69788220,70486813,71164192,71820967,72459097,73080198,73686045,74277263,
74854848,75580173,76281192,76958934,77616432,78254516,78875101,79479726,80069949,80646304,
81209842,81913126,82593642,83252188,83891520,84512425,85116692,85705985,86281927,86844712,
87395222,88078277,88739789,89380423,90002919,90608076,91197276,91772241,92334568,92884400,
93422516,94086078,94729635,95353494,95959931,96550183,97125584,97687286,98236774,98774497,
99300966,99946350,100573004,101181179,101773075,102349517,102911768,103461177,103998784,
104524884,105040134,105668630,106279633,106873231,107451534,108015603,108566044,109104101,
109630965,110146773,110652019,111263448,111858755,112437880,113002507,113553847,114092524,
114619365,115135281,115640682,116135935,116731236,117311723,117877173,118429067,118968504,
119495888,120012050,120517675,121013081,121498549,122246148,122967486,123666231,124344352,
125002221,125641869,126264830,126872397,127465162,128044273,128767360,129465536,130142334,130799782
};
inline int locate(int x){
	return x/10000000;
}
inline bool check(int x){
	register int n=x;int d=0;
	while(n){
		d+=n%10;
		n/=10;
	}
	if(d and x%d==0) return true;
	return false;
}
signed main(){
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	int l,r,anss=0;
	cin>>l>>r;
	if(locate(l)==locate(r) or locate(r)-locate(l)==1){
		for(int i=l;i<=r;++i){
			if(check(i)) anss++;
		}
	}
	else{
		anss=ans[locate(r)-1]-ans[locate(l)];
		for(int i=l;i<=(locate(l)+1)*10000000;++i){
			if(check(i)) anss++;
		}
		for(int i=locate(r)*10000000+1;i<=r;++i){
			if(check(i)) anss++;
		}
	}
	cout<<anss<<endl;
}

打表辅助程序

#include<bits/stdc++.h>
using namespace std;
bool check(int x){
	register int n=x;int d=0;
	while(n){
		d+=n%10;
		n/=10;
	}
	if(d and x%d==0) return true;
	return false;
}
#define int long long
int ans=0,cnt=0;
signed main(){
	for(int i=1;i<=2157483647;++i){
		if(check(i)) ans++;
		if(i%50000000==0){
			cout<<ans<<",";
			cnt++;
			if(cnt==10){
				cout<<endl;
			}
		}
	}
}

一跑觉得还挺快,心想这题包稳了.

结果赛后一测 RE 了,我寻思我表长只有 \(50\) 不太可能炸长度,结果点开一看,测试点是 \(10^{18}\) 的,气死了. 怎么题面还能锅.

也就是个板子题加强版,这里的话显然要根据数位和和原数来转移,判断的话直接取模看看就行,数位 \(sum'=sum+i\),原数 \(num'=10num+i\),这样就写完了一个爆搜.

然后这题要记的话,首先肯定不能直接把 \(num\) 这个 \(10^{18}\) 的范围拿过来开,所以显而易见要取下模再存. 但是取模的话毕竟不是原数,肯定会丢情况,赛时就卡在这了.

实际上题解给出的答案是:那你所有模数全跑一遍不就行了,(这不T?)因为是记搜,最坏复杂度 \(T(2\times 9\times 19\times sizeof_{f})=64980\),再加上 \(memset\) 耗时能过(实际上根本跑不满 \(sizeof_{f}\),不然就该T了).

#include<bits/stdc++.h>
using namespace std;
#define int long long
int f[20][200][200];
int len,a[20],mod;
int dfs(int pos,int sum,int num,int limit){
	if(pos>len){
		if(!sum) return 0;
		if(!num and sum==mod) return 1;
		return 0;
	}
	if(!limit and f[pos][sum][num]!=-1) return f[pos][sum][num];
	int ret=0;
	int res;
	if(limit){
		res=a[len-pos+1];
	}
	else res=9;
	for(int i=0;i<=res;++i){
		ret+=dfs(pos+1,sum+i,(10ll*num+i)%mod,i==res and limit);
	}
	if(limit) return ret;
	else return f[pos][sum][num]=ret;
}
int sol(int r){
	len=0;
	while(r) a[++len]=r%10,r/=10;
	int ans=0;
	for(mod=1;mod<=9*len;mod++){
		memset(f,-1,sizeof f);
		ans+=dfs(1,0,0,1);
	}
	return ans;
}
signed main(){
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
	int l,r;
	cin>>l>>r;
	cout<<sol(r)-sol(l-1);
}

B.千山鸟飞绝

很显然这个题的难点有三个:一个是找坐标,一个是找极值,一个是插入删除

在赛事写了一个有序数列二分查找套手写堆,不用优先队列是因为没办法删除节点,可惜的是并没有调出来

赛时代码(肚子不舒服导致脑子也不太好使,写的比较抽象了,但是确实是有序数列二分查找套手写堆,只不过删除是 \(O(n)\) 的)

#include<bits/stdc++.h>
using namespace std;
const int N=30001;
class direction{
	public:
		map<pair<int,int>,int>d;
		int cnt=0;
		inline int find(int _x,int _y){
			if(!d.count({_x,_y})){
				d[{_x,_y}]=++cnt;
			}
			return d[{_x,_y}];
		}
};
direction di;
struct b{
	int id,ww;
	bool operator ==(const b &x)const{
		if(id==x.id) return true;
		return false;
	}
	bool operator !=(const b &x)const{
		if(id==x.id) return false;
		return true;
	}
	bool operator <(const b &x)const{
		return ww<x.ww;
	}
};
template<typename T>
class ordered_vector{
	public:
		vector<T>v;
		inline int find(T x){
			for(int i=0;i<=(int)v.size()-1;++i){
				if(v[i]==x) return i;
			}
			return v.size();
		}
		inline int lower_bound(T x){
			return (std::lower_bound(v.begin(),v.end(),x)-v.begin());
		}
		inline int size(){
			return v.size();
		}
		inline void insert(T x){
			int pos=lower_bound(x);
			if((pos<=(int)v.size()-1 and (T)v[pos]!=x) or (pos>=(int)v.size())){
				v.insert(v.begin()+lower_bound(x),x);
			}
		}
		inline int it(T x){
			int pos=lower_bound(x);
			return pos;
		}
		inline T maxn(){
			return v.back();
		}
		inline void remove(T id){
			for(int i=0;i<=(int)v.size()-1;++i){
				if(v[i]==id){
					v.erase(v.begin()+i);
					break;
				}
			}
		}
		T operator [](int x){
			return v[x];
		}
};
struct poi{
	ordered_vector<b> m;
	int val;
	bool operator<(const poi &x)const{
		return val<x.val;
	}
	bool operator ==(const poi &x)const{
		if(val==x.val) return true;
		return false;
	}
	bool operator !=(const poi &x)const{
		if(val==x.val) return false;
		return true;
	}
};
ordered_vector<poi> dirs;
int www[N],xx[N],yy[N],maxww[N],maxtj[N];
int main(){
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	int n;
	cin>>n;
	for(int i=1;i<=n;++i){
		int x,y,ww;
		cin>>ww>>x>>y;
		www[i]=ww;
		xx[i]=x;yy[i]=y;
		dirs.insert({{},di.find(x,y)});
		dirs[dirs.it({{},di.find(x,y)})].m.insert({i,ww});
	}
	for(int v=1;v<=n;++v){
		maxtj[v]=max(maxtj[v],dirs[dirs.it({{},di.find(xx[v],yy[v])})].m.size());
		maxww[v]=max(maxww[v],dirs[dirs.it({{},di.find(xx[v],yy[v])})].m.maxn().ww);
	}
	int q;cin>>q;
	for(int i=1;i<=q;++i){
		int v,x,y;
		cin>>v>>x>>y;
		dirs[dirs.it({{},di.find(xx[v],yy[v])})].m.remove(b{v,www[v]});
		xx[v]=x;yy[v]=y;
		dirs.insert({{},di.find(x,y)});
		dirs[dirs.it({{},di.find(x,y)})].m.insert({v,www[v]});
		maxtj[v]=max(maxtj[v],(int)dirs[dirs.it({{},di.find(xx[v],yy[v])})].m.v.size());
		maxww[v]=max(maxww[v],dirs[dirs.it({{},di.find(xx[v],yy[v])})].m.maxn().ww);
	}
	for(int i=1;i<=n;++i){
		cout<<1ll*maxtj[i]*maxww[i]<<endl;
	}
}

然后赛后觉得这个代码还是太抽象了,我自己都懒得调,所以换了一种思路,写的有序数列二分查找套std::map,写起来感觉简单一点,但是这个复杂度肯定是过不了,\(50pts\),隔壁 9G 似乎拿暴力打出来了,看来还是我这个暴力复杂度不够优

平衡树 TBA

posted @ 2024-07-08 11:23  HaneDaniko  阅读(17)  评论(0编辑  收藏  举报
/**/