2021 "MINIEYE Cup" Chinese college students algorithm design super league part of the problem solution

Posted by genius on Fri, 31 Dec 2021 21:14:54 +0100

C.VC Is All You Need

  • meaning of the title
    Here you are n n n points at k k On the k dimension, judge whether you can use k − 1 k-1 k − 1 dimension in 2 n 2^n 2n coloring schemes to separate them. Equivalent to k k In k-dimensional space, find n n The maximum value of n so that you can find n n n points (given their own coordinates) meet: no matter for this n n How do n points dichromate, that is, for 2 n 2^n For each of the 2n dyeing schemes, there is always one k − 1 k-1 The k − 1-dimensional hyperplane strictly separates the points of the two colors.

  • Problem solving ideas
    When n + 1 = k n + 1=k When n+1=k, it must be feasible. We can make k k The k-dimension is different on both sides. And when n ≥ k − 1 n \geq k -1 When n ≥ k − 1, no matter how placed, no side can be consistent.

  • AC code

/**
  *@filename:VC_Is_All_You_Need
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-08-03 12:47
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 100000 + 5;
const int P = 1e9+7;

int t;
ll n,k;
void solve(){
    if(n - k <= 1){
        cout << "Yes" << endl;
    }
    else{
        cout << "No" << endl;
    }
}
int main(){
    cin >> t;
    while(t -- ){
        cin >> n >> k;
        solve();
    }
    return 0;
}

D.Another String

Idea: violence + double pointer
await a vacancy or job opening

  • std
#include<bits/stdc++.h>
#define dd(x) cerr<<#x<<" = "<<x<<" "
#define de(x) cerr<<#x<<" = "<<x<<endl
#define de_arr(a,s,t) cout<<#a<<": ";for (int z=(s);z<=(t);++z)cout<<a[z]<<" ";cout<<endl;
#define sz(x) int(x.size())
#define All(x) x.begin(),x.end()
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> P;
const double eps=1e-8;
const int mod=1e9+7;
inline int sign(double x){return (x>eps)-(x<-eps);}
inline int add(int a,int b){a+=b;return a<0?a+mod:a>=mod?a-mod:a;}
inline int mul(ll a,ll b){return a*b%mod;}
const int maxn=5e3+10,INF=0x3f3f3f3f;
char s[maxn];
int f[maxn][maxn],cnt[maxn][maxn],pt[maxn];
ll ANS[maxn];
void calc_f(int n,int k){
    for (int st=2;st<=n;++st){
        int dif=0;
        for (int i=1,j=st,len=-1; j<=n; ++i,++j,--len){
            while (i+len+1<=n&&j+len+1<=n&&dif<=k){
                len++; 
                dif+=s[i+len]!=s[j+len];
            }
            f[i][j]=len+(dif<=k);
            dif-=s[i]!=s[j];
        }
    }
}
void solve(int n){
    for (int i=0;i<=n;++i){
        pt[i]=n/2+1;
        for (int j=0;j<=n;++j)
            cnt[i][j]=0;
    }
    ll ans=0;
    for (int j=n;j>1;--j){
        //update
        for (int i=1;i<j;++i)
            while (pt[i]>j-i){
                ans-=cnt[i][pt[i]];
                cnt[i][pt[i]-1]+=cnt[i][pt[i]];
                pt[i]--;
            }
        //add
        for (int i=1;i<j;++i){
            int len=min(f[i][j],j-i);
            cnt[i][len]++;
            ans+=len;
        }
        ANS[j]=ans;
        //delete
        while (pt[j-1]>=0){
            ans-=ll(cnt[j-1][pt[j-1]])*pt[j-1];
            pt[j-1]--;
        }
    }
}
int main()
{
    int T;
    cin>>T;
    while (T--){
        int n,k;
        scanf("%d%d%s",&n,&k,s+1);
        calc_f(n,k);
        solve(n);
        for (int i=2;i<=n;++i)
            printf("%d\n",ANS[i]);
    }
    return 0;
}
 

F.Cute Tree

  • meaning of the title
    Give you a tree building function, which can generate several nodes.

  • Problem solving ideas
    It is feasible to write the tree building function according to the meaning of the topic. We only need to care about the interval length. In order to reduce the number of recursive layers, the l o g 3 n log_3n log3 n, so we need to use hash table to memorize information.

  • AC code

/**
  *@filename:Cute_Tree
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-08-03 12:13
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 100000 + 5;
const int P = 1e9+7;

int t,n;
unordered_map<ll,ll> p;
ll buildTree(int len){
    if(p[len])return p[len];
    if(len == 1){
        return 1;
    }
    if(len == 2){
        return p[len] = buildTree(len / 2) + buildTree(len - len / 2) + 1;
    }
    else{
        if(len % 3 == 0){
            return p[len] = buildTree(len / 3) + buildTree(len / 3) + buildTree(len / 3) + 1;
        }
        else if(len % 3 == 1){
            return p[len] = buildTree(len / 3) + buildTree(len / 3) + buildTree(len / 3 + 1) + 1;
        }
        else{
            return p[len] = buildTree(len / 3 + 1) + buildTree(len / 3) + buildTree(len / 3 + 1) + 1;
        }
    }
}
void solve(){
    printf("%lld\n", buildTree(n));
}
int main(){
    scanf("%d", &t);
    while(t -- ){
        scanf("%d", &n);
        int x;
        for(int i = 1; i <= n; ++ i){
            scanf("%d", &x);
        }
        solve();
    }
    return 0;
}

G.Banzhuan

  • meaning of the title
    Here you are n × n × n n\times n\times n n × n × Empty of n c u b e cube Cube, where the cost of placing a unit cube is related to its initial placement position, that is, if it is placed in ( x , y , z ) (x,y,z) (x,y,z), then the price is x y 2 z xy^2z xy2z, the unit placed in it will fall under the influence of gravity until there is a cube at the bottom or reach the bottom. Calculate the cost when the three views are square in the past.

  • Problem solving ideas
    For the most expensive case, obviously we need to fill it up n × n × n n \times n \times n n × n × N, and in order to maximize the cost, each brick needs to be dropped from the highest place, so there is the maximum cost: ∑ x = 1 n ∑ y = 1 n ∑ z = 1 n x × y 2 × n = n 2 × ( n + 1 ) n 2 × n ( n + 1 ) ( 2 n + 1 ) 6 \sum_{x=1}^{n}\sum_{y=1}^{n}\sum_{z=1}^{n}x \times y^2 \times n=n^2 \times \frac {(n+1)n}{2} \times \frac {n(n+1)(2n+1)}{6} ∑x=1n​∑y=1n​∑z=1n​x×y2×n=n2×2(n+1)n​×6n(n+1)(2n+1)​.
    For the case of minimum cost, it is obvious that we must pave the bottom, so we can ignore the top view. For the front view and left view, if we want to reduce the cost, we must make x , y x,y x. Y is as small as possible, then both sides take 1 1 1 is the smallest, which means that we just need to build it ( x ≥ 2 , y = 1 ) , ( y ≥ 2 , x = 1 ) (x\geq 2,y=1),(y\geq2,x=1) (x ≥ 2,y=1),(y ≥ 2,x=1) is sufficient. Namely: ∑ x = 1 n ∑ y = 1 n x × y 2 + ∑ x = 2 n ∑ z = 2 n x z + ∑ y = 2 n ∑ z = 2 n y 2 z = n ( n + 1 ) 2 × n ( n + 1 ) ( 2 n + 1 ) 6 + ( n + 2 ) 2 ( n − 1 ) 2 4 + ( n + 2 ) ( n − 1 ) 2 × ( n ( n + 1 ) ( 2 n + 1 ) 6 − 1 ) \sum_{x=1}^{n}\sum_{y=1}^{n}x \times y^2+\sum_{x=2}^n\sum_{z=2}^nxz+\sum_{y=2}^n\sum_{z=2}^ny^2z=\frac{n(n+1)}{2}\times \frac{n(n+1)(2n+1)}{6}+\frac{(n+2)^2(n-1)^2}{4}+\frac{(n+2)(n-1)}{2}\times (\frac{n(n+1)(2n+1)}{6}-1) ∑x=1n​∑y=1n​x×y2+∑x=2n​∑z=2n​xz+∑y=2n​∑z=2n​y2z=2n(n+1)​×6n(n+1)(2n+1)​+4(n+2)2(n−1)2​+2(n+2)(n−1)​×(6n(n+1)(2n+1)​−1).

  • AC code

/**
  *@filename:banzhuan
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-08-03 12:58
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 100000 + 5;
const ll P = 1e9+7;

int t;
ll n;
ll qsm(ll n, ll q){
    ll ans = 1;
    while(q){
        if(q & 1)ans = ans % P * n % P;
        n = n % P * n % P;
        q >>= 1;
    }
    return ans;
}
void solve(){
    n %= P;
    //a is n * (n + 1) / 2, b is n * (n + 1) * (2 * n + 1) / 6
    ll a = n * (n + 1) % P * qsm(2,P - 2) % P, 
    b = n * (n + 1) % P * (2 * n + 1) % P * qsm(6,P - 2) % P;
    cout << (a * b % P + (a - 1) * (a - 1) % P + (b - 1) * (a - 1) % P) % P << endl;
    cout << a * b % P * (n % P) % P * (n % P) % P << endl;//max
}
int main(){
    cin >> t;
    while(t -- ){
        cin >> n;
        solve();
    }
    return 0;
}

I.Array

Idea: line segment tree / tree array + difference
await a vacancy or job opening

  • std
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
const int N=2e6+3;
vector<int>G[N];
int main(){
	ios::sync_with_stdio(0);cin.tie(0);
	int n,t;
	using namespace myFuction;
	print();
	cin>>t;
	while(t--){
		cin>>n;
		unordered_set<int>s;
		vector<int>a(n+1);
		for(int i=1;i<=n;++i){
			cin>>a[i]; s.insert(a[i]); G[a[i]].pb(i);
		}
		ll ans=0;
		for(auto num:s){ // Enumerate each number as a mode 
			ll res=0;// answer 
			ll sum=0;// Current prefix and
			unordered_map<int,int>f1,f2;// There are f1[sum] points with prefix sum 
			G[num].pb(n+1);
			ll k=0,minn=0;
			for(int j=1;j<=n;++j){
				if(j>G[num][k]) k++;
				if(a[j]!=num&&sum==minn){
					ll len=G[num][k]-j-1;
					f2[sum+1]--;
					f2[sum-len]++;
					j+=len;
					sum-=len+1;
				}
				else if (a[j]==num){
					f1[sum]+=f2[sum];
					f2[sum+1]+=f2[sum];
					f2[sum]=0;
					f1[sum]++;
					res+=f1[sum];
					sum++;
					ans+=res;
				}
				else{
					f1[sum]++;
					sum--;
					res-=f1[sum];
					ans+=res;
				}
				if(minn>sum)minn=sum;
			}
			
		}
		cout<<ans<<'\n';
		for(auto &i:s)G[i].clear();
	}
	return 0;
}

Topics: Algorithm Dynamic Programming divide and conquer