DEFI

D. Drop Voicing

题意:

给你一个数列,你可以进行两种操作。
Drop-2: 将n-1位置的数移到第一个位置,变成 pn1p1p2pn3pn2pn。
Invert: 将第一个数移动到最后一个位置,变成  p2pn−3pn−2pn1,pn, p1
每次操作可以选择一种不限次数的移动,问Drop-2操作最少几次。

题解:

比赛的时候看这样例突然就有了想法,感觉就是不在自己该在的地方的数才需要Drop-2变换,也就是说找到先最长升序数列(LIS),然后剩下的数操作一次Drop-2应该就可以变换到他该去的地方,只要用数列长度减去LIS就好了。因为Invert操作并不需要考虑他的次数,所以可以先操作Invert,找到一个排序的LIS最大,然后再用数列长度减去。但是至于对不对,我也不太会证明.... 作为一个菜鸡,大胆猜测,直接交一发验证(逃。可以看看这个巨巨的证明,感觉讲的蛮清楚的了。

代码

#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pb push_back
#define ft first
#define sd second
#define pii pair<int,int>
#define pll pair<ll,ll>
using namespace std;

int a[100100],b[510];
int dp[510];
const int INF=0x3f3f3f3f;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n;
    cin>>n;
    int ans=-1;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int k=0;k<n;k++){
        for(int i=0;i<n;i++) dp[i]=INF,b[i]=a[(i+k)%n];
        for(int i=0;i<n;i++){
            int p=lower_bound(dp,dp+n,b[i])-dp;
            ans=max(ans,p+1);
            dp[p]=b[i];
        }
    }
    cout<<n-ans<<endl;
    return 0;
}

E. Bogo Sort

题意

给定一个置换,问有多少个排列可以通过若干次该置换变成1....N的排列。结果对10^N取模

题解

  • 由于长度总和是n,所以一定不会大于位数,不需要取模。
  • 写几组观察可以看出结果就是所有环的lcm,然后用大数运算。

代码

贴上队友巨巨的代码
#include<bits/stdc++.h>
#define ull unsigned long long 
#define ll long long
#define pb push_back
#define ft first
#define sd second
#define pii pair<int,int>
#define pll pair<ll,ll>
using namespace std;

const int maxn = 1e5+5;
int a[maxn];

vector<int> cheng(int x,vector<int> vv)
{
    vector<int> ans;
    int t=0;
    int i;
    for (i=0;i<vv.size();i++)
    {
        t=t+vv[i]*x;
        ans.push_back(t%10);
        t/=10;
    }
    while (t>0)
    {
        ans.push_back(t%10);
        t/=10;
    }
 
    return ans;
}

int num[maxn];
int vis[maxn];

int main()
{
    int n;
    scanf("%d",&n);
    for (int  i=1 ; i <= n; i ++ )
    {
        scanf("%d",&a[i]);
    }
    std::vector<int> ans;
    ans.pb(1);
    int gc = 0;
    int ftemp = 0;
    for (int i = 1; i <= n; i ++ )
    {
        if(vis[i] == 0)
        {
            int s= 0 ;
            int  k= i;
            while(vis[k] == 0)
            {
                vis[k] = 1;
                // printf("%d ",k);
                k = a[k];
                s ++ ;
                 
            }
            ftemp ++ ;
            for (int i = 2; i * i <= s; i ++ )
            {
                int cnt = 0;
                while(s % i == 0)
                {
                    s /= i;
                    cnt ++ ;
                }
                num[i] = max(num[i],cnt);
            }
            if(s > 1)
            {
                num[s] = max(num[s],1);
            }
        }
    }
    for (int i = 2; i <= n; i ++ )
    {
        for (int j = 0; j < num[i]; j ++ )
        {
            ans = cheng(i,ans);
        }
    }
    int f = 1;
    for (int i = min(n - 1,(int)ans.size()) - 1; i >= 0; i -- )
    {
        if(ans[i] != 0 || f == 0)
        {
            f =0 ;
            printf("%d",ans[i]);
        }
    }
    printf("\n");
}


F. DPS

题意

输出一个图形。,si就是图中 ‘-’ 的数量。如果当前 di==maxid的话,就要在中间那行的 '|' 前边输出一个 ‘*’ 。

题解

记得开long long ,因为算 si 的时候 d 的最大范围*50的话会超过long long

代码

#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pb push_back
#define ft first
#define sd second
#define pii pair<int,int>
#define pll pair<ll,ll>
using namespace std;
 
ll a[10010];
 
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    ll n;
    cin>>n;
    ll maxn=0;
    for(ll i=0;i<n;i++) cin>>a[i],maxn=max(maxn,a[i]);
    for(ll i=0;i<n;i++){
        ll p=(50*a[i]+maxn-1)/maxn;
        cout<<"+";
        for(ll i=0;i<p;i++) cout<<"-";
        cout<<"+"<<endl;
 
        cout<<"|";
        if(a[i]==maxn){
            for(ll i=0;i<p-1;i++) cout<<" ";
            cout<<"*|";
            cout<<a[i]<<endl;
        }
        else{
 
            for(ll i=0;i<p;i++) cout<<" ";
            cout<<"|";
            cout<<a[i]<<endl;
        }
 
        cout<<"+";
        for(ll i=0;i<p;i++) cout<<"-";
        cout<<"+"<<endl;
    }
    return 0;
}

I. Hard Math Problem

题意

每一个H的周围至少要有一个G和一个E,f (n,m) 代表n*m的格子中H的最大数量是多少。求

题解

(i+j)%3 =0 交错2和3 

答案是2/3 

因为这样每个1旁边恰好有一个2和3,而任意两个2和3不相邻。

可以计算出这是上限。

代码

#include <cstdio>
#include <iostream>
using namespace std;
int main(){
    printf("0.666667\n");
    return 0;
}