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
标签:dirs,return,di,int,一小,long,学期,find From: https://www.cnblogs.com/HaneDaCafe/p/18289575