zoukankan      html  css  js  c++  java
  • 美团杯 2021【杂题】

    感觉上还是去年好啊。

    以下按照讲题顺序排列。

    I 24点

    Small Task:做 24 点。

    网上随便搜个代码下来跑。

    Large Task:对于所有有解的 24 点题,求中间结果的最小值的最大值,和最大值的最小值。

    用同样的代码爆搜,上界是 ((13*13-1)/7=24)(r=169),下界的话看到 Small Task 里有一个 (2/13) 的,并且不太搜的出来更小的,直接交上去就过了。

    K 杳瑶寺吴遥寺

    给定整数 (n),求 ({1,1,4,5,1,4} imesinfty) 的最短前缀 (A_1,A_2,cdots,A_m) 的长度 (m),满足存在把 (A_1otimes A_2otimescdotsotimes A_m) 中的 (otimes) 替换为 (+)(-) 的方案,使得其值为 (n)

    (|n|le 10^9),Small Task:(|n|le 10^6)

    solution

    考虑 dp 过程,(f_{i,j}) 表示前 (i) 个数是否能凑出 (j),发现状态只用记 (imod 6),变为类似 bfs 的过程。

    (|n|) 太大的时候后就用一堆同符号的循环节。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=6666666,mod=998244353,add[]={1,1,4,5,1,4};
    #define fi first
    #define se second
    #define PB push_back
    #define MP make_pair
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    template<typename T>
    inline void read(T &x){
    	x=0;
    	bool f=0;char ch=getchar();
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	if(f) x=-x;
    }
    int n,h,r;
    PII q[maxn];
    map<int,int> f[6],s;
    void solve(){
    	read(n);
    	if(abs(n)<=2000) printf("%d
    ",s[n]);
    	else if(n>=0) printf("%d
    ",s[n%16+992]+(n-992)/16*6);
    	else printf("%d
    ",s[-(-n)%16-992]+(-992-n)/16*6);
    }
    int main(){
    	f[1][1]=1;
    	q[h=r=1]=MP(1,1);
    	while(h<=r && r<=5e5){
    		PII p=q[h++];
    		int i=p.first,j=p.second;
    		int ii=i+add[j],jj=(j+1)%6;
    		if(!f[jj].count(ii)){
    			f[jj][ii]=f[j][i]+1;
    			q[++r]=MP(ii,jj);
    		}
    		ii=i-add[j],jj=(j+1)%6;
    		if(!f[jj].count(ii)){
    			f[jj][ii]=f[j][i]+1;
    			q[++r]=MP(ii,jj);
    		}
    	}
    	FOR(i,-2000,2000){
    		int ans=1e9;
    		FOR(j,0,5) if(f[j].count(i)) ans=min(ans,f[j][i]);
    		s[i]=ans;
    	}
    	int T;
    	read(T);
    	while(T--) solve();
    }
    

    M 游泳

    给定正整数 (n,m,K),求长为 (m)、和为 (n)、相邻数字差 (le K) 的正整数序列 (A) 的方差最大值。

    solution

    贪心地让各个数差距尽量大即可。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=100010,mod=998244353;
    #define fi first
    #define se second
    #define PB push_back
    #define MP make_pair
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    template<typename T>
    inline void read(T &x){
    	x=0;
    	bool f=0;char ch=getchar();
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	if(f) x=-x;
    }
    int n,m,k,c[maxn];
    void solve(){
    	read(n);read(m);read(k);
    	if(n<m) return puts("-1"),void();
    	if(!k){
    		if(n%m) puts("-1");
    		else puts("0");
    		return;
    	}
    	int nn=n;
    	FOR(i,1,m) c[i]=1;
    	n-=m;
    	FOR(i,1,m){
    		ll tmp=1ll*i*k;
    		if(tmp>n || i==m){
    			int d=n/i,r=n%i;
    			FOR(j,1,i) c[j]+=d;
    			ROF(j,i,i-r+1) c[j]++;
    			break;
    		}
    		n-=tmp;
    		FOR(j,1,i) c[j]+=k;
    	}
    	ll ans=0;
    	FOR(i,1,m) ans+=1ll*c[i]*c[i];
    	ans*=m;
    	ans-=1ll*nn*nn;
    	printf("%lld
    ",ans);
    } 
    int main(){
    	int T;
    	read(T);
    	while(T--) solve();
    }
    

    A 数据结构

    给定长为 (n) 的正整数序列 (a_i)(m) 次询问 (l,r),表示给 (a[l:r]) 加上 (1) 之后求全局不同数的个数,并撤销修改(即询问之间互相独立)

    (n,mle 10^6),Small Task:(nle 5000)

    solution

    考虑每个数 (i) 不出现的条件:设 (i) 的出现位置是 (b_{i,1},b_{i,2},cdots,b_{i,c_i}),则 (lle b_{i,1})(rge b_{i,c_i})([l,r]) 不包含所有的 (b_{i-1,j})

    这是 (O(n)) 个矩形加,(O(m)) 个单点求值,扫描线+BIT 即可。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=1111111,mod=998244353;
    #define fi first
    #define se second
    #define PB push_back
    #define MP make_pair
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    template<typename T>
    inline void read(T &x){
    	x=0;
    	bool f=0;char ch=getchar();
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	if(f) x=-x;
    }
    int n,m,a[maxn],ql,ans[maxn];
    vector<int> v[maxn];
    struct ques{
    	int x,l,r,tp;
    	bool operator<(const ques &q)const{
    		if(x!=q.x) return x<q.x;
    		return abs(tp)>abs(q.tp);
    	}
    }q[maxn*5];
    inline void add(int xl,int yl,int xr,int yr){
    	q[++ql]=(ques){xl,yl,yr,1};
    	q[++ql]=(ques){xr+1,yl,yr,-1};
    }
    int b[maxn];
    inline void update(int p,int v){
    	for(int i=p;i<=n;i+=i&-i) b[i]+=v;
    }
    inline int query(int p){
    	int s=0;
    	for(int i=p;i;i-=i&-i) s+=b[i];
    	return s;
    }
    int main(){
    	read(n);read(m);
    	FOR(i,1,n) read(a[i]);
    	FOR(i,0,n+1) v[i].PB(0);
    	FOR(i,1,n) v[a[i]].PB(i);
    	FOR(i,0,n+1) v[i].PB(n+1);
    	FOR(i,1,n+1){
    		int mn=1e9,mx=-1e9;
    		FOR(j,1,(int)v[i].size()-2) mn=min(mn,v[i][j]),mx=max(mx,v[i][j]);
    		if(mn==1e9){
    			FOR(j,0,(int)v[i-1].size()-2)
    				add(v[i-1][j]+1,v[i-1][j]+1,v[i-1][j+1]-1,v[i-1][j+1]-1);
    		}
    		else{
    			int mn2=1e9,mx2=-1e9;
    			bool flag=false;
    			FOR(j,0,(int)v[i-1].size()-1){
    				int x=v[i-1][j];
    				if(x>=mn && x<=mx){flag=true;break;}
    				if(x<mn) mx2=max(mx2,x);
    				if(x>mx) mn2=min(mn2,x);
    			}
    			if(flag) continue;
    			add(mx2+1,mx,mn,mn2-1);
    		}
    	}
    	FOR(i,1,m){
    		int l,r;
    		read(l);read(r);
    		q[++ql]=(ques){l,r,i,0};
    	}
    	sort(q+1,q+ql+1);
    	FOR(i,1,ql){
    		if(q[i].tp){
    			update(q[i].l,q[i].tp);
    			update(q[i].r+1,-q[i].tp);
    		}
    		else{
    			ans[q[i].r]=query(q[i].l);
    		}
    	}
    	FOR(i,1,m) printf("%d
    ",n+1-ans[i]);
    }
    

    C 查查查乐乐II

    给定正整数 (n)(forall kin[1,n]),求 (长度,字典序) 最小的 ( exttt{xl}) 字符串,满足 ( exttt{xxxll}) 的个数为 (k)

    (n=10^5),Small Task:(n=100)

    solution

    考虑对一个字符串求 ( exttt{xxxll}) 的个数:枚举第 (3)( exttt x),设左边有 (a)( exttt x),右边有 (b)( exttt l),贡献是 (inom a2inom b2)

    考虑 dp:枚举总共有多少个 ( exttt l),然后 (f_{i,j,k}) 表示当前有 (i)( exttt x),之后有 (j)( exttt l),已有 (k)( exttt{xxxll}) 是否可行。

    跑一下发现串长 (le 37),所以 (i,j) 都只有 (37)。复杂度 (O(37^3n/w))

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 100003, M = 31, INF = 0x3f3f3f3f;
    int n, coe[M][M], len[N];
    bitset<N> f[M][M];
    bool str[M<<1], ans[N][M<<1];
    int main(){
    	scanf("%d", &n);
    	memset(len, 0x3f, sizeof len);
    	for(int i = 2;i < M;++ i)
    		for(int j = 2;j < M;++ j)
    			coe[i][j] = i*(i-1)*j*(j-1)>>2;
    	for(int px = 3;px < M;++ px){
    		for(int x = 0;x <= px;++ x)
    			for(int l = 0;l < M;++ l) f[x][l].reset();
    		f[0][0].set(0);
    		for(int x = 0;x <= px;++ x)
    			for(int l = 0;l < M;++ l){
    				if(x < px) f[x+1][l] |= f[x][l]<<coe[px-x-1][l];
    				if(l+1 < M) f[x][l+1] |= f[x][l];
    			}
    		for(int i = 1;i <= n;++ i){
    			int pl = INF;
    			for(int j = 0;j < M;++ j)
    				if(f[px][j][i]){pl = j; break;}
    			if(px + pl > len[i]) continue;
    			int x = px, l = pl, cur = i, ha = 0;
    			while(x || l)
    				if(l && f[x][l-1][cur]){-- l; str[ha++] = 0;}
    				else {cur -= coe[px-x][l]; -- x; str[ha++] = 1;}
    			if(ha < len[i]){
    				memcpy(ans[i], str, ha);
    				len[i] = ha;
    			} else {
    				for(int j = 1;j <= ha;++ j)
    					if(ans[i][j] > str[j]){
    						memcpy(ans[i], str, ha); break;
    					} else if(ans[i][j] < str[j]) break;
    			}
    		}
    	}
    	for(int i = 1;i <= n;++ i){
    		if(len[i] == INF){puts("-1"); continue;}
    		for(int j = 0;j < len[i];++ j)
    			putchar(ans[i][j] ? 'x' : 'l');
    		putchar('
    '); 
    	}
    }
    

    H 哈利波特

    这是一道提交答案题

    给定长为 (4807976) 的小写字符串 (s)(370103) 个英文单词的字典 (D)

    定义串 (s) 对字典 (D) 的分词代价 (f(D,s)) 是将 (s) 最小划分子串个数,使得每个子串都是 (D) 中的单词。

    定义 (D) 中单词 (w) 的阿瓦达指数是 (s)(Dackslash{w}) 的分词代价。

    求所有长度 (>1) 的单词 (w) 的 (阿瓦达指数,字典序) 的前 (K) 大值。

    (K=200),Small Task:(K=2)

    solution
    完全不会,被智商碾压了(

    暴力方法是把 (f(D,s)) 中用到的单词 (w) 取出来跑。

    正解是估价函数:设 ( ext{way}(w))(f(D,s))(w) 的出现次数,则 (f(Dackslash{w},s)le f(D)+ ext{way}(w)(f(Dackslash{w},w)-1)),只有在这个值 (ge) 当前第 (K) 大时才做。

    经测试,直接按照给的字典跑需要判 (1933) 个词,运行时间 (419 ext s),如果先把单词按 (长度,字典序) 排序就只用判 (1626) 个词,运行时间 (322 ext s),稍微优了一点,但前者判出来的很多都是认识的单词,可以更方便地提取出一篇文章中的常用单词。有点好玩,想再找一篇文章看看

    #include<bits/stdc++.h>
    #define PB emplace_back
    #define MP make_pair
    #define fi first
    #define se second 
    using namespace std;
    typedef pair<int, int> pii;
    const int N = 4808000, K = 370103;
    template<typename T>
    bool chmin(T &a, const T &b){if(a > b) return a = b, 1; return 0;}
    FILE *f1 = fopen("dict.in", "r"), *f2 = fopen("harry-potter.txt", "r");
    int n, ch[N][26], tot, len[K+5], id[N], dp[N], way[K+5], pre[N], all;
    char str[N], ss[K+5][33];
    int work(int n, int k, char *str){
    	memset(dp, 0x7f, n+1<<2);
    	dp[0] = 0;
    	for(int i = 0;i < n;++ i)
    		for(int j = i+1, u = 0;j <= n;++ j){
    			u = ch[u][str[j]-'a'];
    			if(!u) break;
    			if(id[u] && id[u] != k) chmin(dp[j], dp[i] + 1);
    		}
    	return dp[n];
    }
    bool cmp(const pii &a, const pii &b){
    	if(a.fi != b.fi) return a.fi > b.fi;
    	return strcmp(ss[a.se]+1, ss[b.se]+1) < 0;
    }
    struct Cmp {bool operator()(const pii &a, const pii &b){return cmp(a, b);}};
    priority_queue<pii, vector<pii>, Cmp> pq;
    vector<pii> ans;
    int main(){
    	fscanf(f2, "%s", str+1);
    	n = strlen(str+1);
    	for(int i = 1;i <= K;++ i){
    		fscanf(f1, "%s", ss[i]+1);
    		int u = 0;
    		len[i] = strlen(ss[i]+1);
    		for(int j = 1;j <= len[i];++ j){
    			int c = ss[i][j]-'a';
    			if(!ch[u][c]) ch[u][c] = ++tot;
    			u = ch[u][c];
    		}
    		id[u] = i;
    	}
    	memset(dp, 0x7f, n+1<<2);
    	dp[0] = 0;
    	for(int i = 0;i < n;++ i)
    		for(int j = i+1, u = 0;j <= n;++ j){
    			u = ch[u][str[j]-'a'];
    			if(!u) break;
    			if(id[u] && chmin(dp[j], dp[i] + 1)) pre[j] = id[u];
    		}
    	all = dp[n];
    	for(int i = n;i;i -= len[pre[i]]) ++ way[pre[i]];
    	for(int i = 1;i <= K;++ i)
    		if(len[i] > 1 && (pq.size() < 200 || cmp(MP(all + way[i]*(work(len[i],i,ss[i])-1), i), pq.top()))){
    			pq.push(MP(work(n,i,str), i));
    			if(pq.size() > 200) pq.pop();
    			printf("ss[%d] = %s
    ", i, ss[i]+1);
    		}
    	while(!pq.empty()){ans.PB(pq.top()); pq.pop();}
    	reverse(ans.begin(), ans.end());
    	for(pii _ : ans) printf("%s %d
    ", ss[_.se]+1, _.fi);
    }
    

    E 程序解谜II

    C++ 代码拼图。

    solution

    跟去年某道题差不多,凭借对竞赛代码的理解拼一拼就可以了。

    注意拼的时候不要把碎片放在一起了,不然错了很难改(

    Large Task 需要用样例算表,不是很难,根据代码中的计算部分反推一下即可。

    #include<cstdio>
    using namespace std;
    namespace Sub2 {
    int clude[50] = {518020025,227984854,990919605,760559275,252747709,351267635,436520588,849336757,847045033,785731263,491533093,243893699,119202559,255782057,101925721,153701673,19279237,757203511,602780864,17233756,503674646,198732600,529032347,789861212,282845866,618483948,252931964,585966855,47548815,458761589,580505477,569964015,505577677,411118499,788281248,963908046,733289631,512853327,257612428,669701279,74200836,267681712,565463498,475616488,358569984,846564286,362377870,890855192,553545630,323150357};
    int n; 
    int v[50], tmp;
    int maine(bool nclude){
    	int mai = 0;
    	for(int i = 0;i < n;++ i){
    		if((i&1)^nclude){
    			tmp = v[i]^clude[i];
    		} else {
    			tmp = ((1<<30)-1)^v[i]^clude[i];
    		}
    		if(tmp > mai) mai = tmp;
    	}
    	return mai;
    }
    void main(){
    	int t;
    	scanf("%d%d", &t, &n);
    	for(int i = 0;i < t;++ i){
    		for(int j = 0;j < n;++ j)
    			scanf("%d", v + j);
    		printf("%d
    ", maine(i&1));
    	}
    }
    }
    namespace Sub1 {
    int t;
    int solve1(int n){
    	t = 0;
    	for(int i = 1;i <= n;++ i)
    		if(n % i == 0) t += 1;
    	return t;
    }
    int solve2(int n){
    	t = 0;
    	for(int i = 2;i <= n;++ i)
    		if(n % i == 0){t += i; while(n % i == 0) n /= i;}
    	return t;
    }
    void main(){
    	int t;
    	scanf("%d", &t);
    	while(t --){
    		int n;
    		scanf("%d", &n);
    		printf("%d
    ", solve1(n)+solve2(n));
    	}
    }
    }
    int main(){
    	int sub;
    	scanf("%d", &sub);
    	if(sub == 1) Sub1 :: main();
    	else Sub2 :: main();
    }
    

    F 面向对象

    给定如下的残缺 C++ 代码,求将 /*MissingModifier*/ 替换为 privateprotectedpublic/*MissingMethod*/ 替换为 method#Num 的方案数,使得编译通过。

    class Class1 {
      void method1() {
        /*MissingMethod*/();
      }
      /*MissingModifier*/:
      void method2() {}
    };
    class Class2: /*MissingModifier*/ Class1 {
      /*MissingModifier*/:
      void method3() {}
      /*MissingModifier*/:
      void method4() {}
    };
    int main() {
      Class2 o2;
      o2./*MissingMethod*/();
    }
    

    保证类的继承关系是树。类有 (300) 个,函数有 (1000) 个。

    solution

    咕了

    J 随机数

    这是一道交互题

    给定一个位运算 random device,你可以调用它 (2000) 次,然后 (100) 次模拟出它跑 (x) 次的结果。

    全局变量 (le 3) 个。

    solution

    考场上看错题了,挨打(

    只要看对题就会发现,如果把全局变量看做 (192) 位向量,这个东西就是线性变换。

    根据 Cayley-Hamilton 定理,它有 (192) 阶齐次线性递推式,用多项式取模的方法做即可。

    懒得拉 BM 板子了,求线性递推式可以暴力高消,复杂度 (O(w^3+Qwlog k))

    #include"interactor.h"
    #include"bits/stdc++.h"
    using namespace std;
    typedef unsigned long long u64;
    namespace {
    const int N = 193, M = N<<1;
    u64 a[2000];
    bitset<N> f[N], g;
    bitset<M> A[30], cur, dif;
    int m;
    bitset<M> mul(const bitset<M> &a, const bitset<M> &b){
    	bitset<M> c;
    	for(int i = 0;i < m;++ i) if(a[i]) c ^= b<<i;
    	for(int i = m-1;~i;-- i) if(c[i+m]) c ^= dif<<i;
    	return c;
    }
    void work(int k){
    	for(int i = 29;~i;-- i) if(k>>i&1) cur = mul(cur, A[i]);
    }}
    void solve(int ifYouDontKnowHowToNameAParameterThenYouUseIt){
    	for(int i = 0;i < 2000;i ++) a[i] = random_ull();
    	for(int i = 0;i < N;++ i)
    		for(int _ = 0;_ < 64;++ _){
    			for(int j = 0;j < N;++ j)
    				g[j] = a[i+j]>>_&1;
    			for(int j = 0;j < N;++ j) if(g[j]){
    				if(f[j][j]) g ^= f[j];
    				else {f[j] = g; break;}
    			}
    		}
    	for(int i = N-1;~i;-- i)
    		if(f[i][i]){
    			bool tmp = 0;
    			for(int j = i+1;j < N;++ j)
    				tmp ^= dif[j] && f[i][j];
    			dif[i] = tmp;
    		} else dif[i] = 1;
    	for(m = N-1;!dif[m];-- m);
    	A[0][1] = 1; cur[0] = 1;
    	for(int i = 0;i < 29;++ i) A[i+1] = mul(A[i], A[i]);
    	work(1999);
    }
    u64 query(int k){
    	work(k); u64 res = 0;
    	for(int i = 0;i < m;++ i) if(cur[i]) res ^= a[i];
    	return res;
    }
    

    L 挑战出题人

    构造在下图的 0 替换为 ([x,3]) 中的整数,使得 loopy 有唯一解。

    0   0   000 
    00 00  0   0
    0 0 0  0   0
    0 0 0  0000 
    0 0 0  0    
    0   0  0    
                
    0  0   00000
    0 0      0  
    00   0 0 0  
    0 0  0 0 0  
    0  0 000 0  
    

    (x=1),Small Task:(x=0)


    Small Task:显然让答案非常小即可。

    Large Task:没听懂,掉线了。

    G 字符串匹配

    这是一道交互题

    交互器有 ( exttt{01})(a),给定 ( exttt{01})(b),你每次可以询问带通配符的串 (s) 和两个下标 (0le lle rle|a|-|s|),交互器告诉你最小和最大的满足 (a[i:i+|s|-1])(s) 匹配的下标 (i),代价是 (C+(r-l+1)w(s)),其中 (w(s))(s) 中非通配符个数,要求代价总和 (le S)

    (b) 是否是 (a) 的子串,如果是,求下标 (i) 使得 (a[i:i+|s|-1]=b)

    (|a|=75000)(|b|=50000)(C=30000)(S=4cdot 10^6)


    咕咕咕咕。

  • 相关阅读:
    要读的书
    装好卫生间的三大要素
    效率由心生,快速提高工作效率秘诀
    玄关装饰设计5大形式
    客厅吊顶装修设计技巧
    如何去除木质家具的污垢
    讲一下SqlDataReader的关闭问题,出现"阅读器关闭时尝试调用 FieldCount 无效"
    SQL SERVER 中如何使用行锁
    汤唯:《在街头卖艺的那些日子》
    【转】取模(mod)与取余(rem)的区别——Matlab学习笔记
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/15002343.html
Copyright © 2011-2022 走看看