2020牛客暑期多校训练营(第五场)F、I、E、D

F DPS

题目传送门

DPS

思路

#include
#include
#include
#include
using namespace std;
// #define TDS_ACM_LOCAL
const int N=109;
typedef long long ll;
ll n, a[N], mx=0;
void solve(ll d){
    cout<<"+";
    int s=ceil((50.0*d)/mx);
    for(int i=0; i<s; i++)  cout<<"-";
    cout<<"+\n|";
    for(int i=0; i<s-1; i++)    cout<<" ";
    if(s!=0)    cout<< (d==mx ? "*":" ");
    cout<<"|"<<d<<endl;
    cout<<"+";
    for(int i=0; i<s; i++)  cout<<"-";
    cout<<"+\n";
}   

int main(){
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
#ifdef TDS_ACM_LOCAL
    freopen("D:\\VS code\\.vscode\\testall\\in.txt", "r", stdin);
    freopen("D:\\VS code\\.vscode\\testall\\out.txt", "w", stdout);
#endif
    cin>>n;
    for(int i=0; i<n; i++){
        cin>>a[i];
        if(a[i]>mx) mx=a[i];
    }
    for(int i=0; i<n; i++)  solve(a[i]);
    return 0;
}

I Hard Math Problem

题目传送门

Hard Math Problem

思路

直接看官方题解吧
• (i+j)%3 =0 交错2和3 • 答案是2/3
• 因为这样每个1旁边恰好有一个2和3,而任意两个2和3不相邻。
• 可以计算出这是上限。

代码

#include
int main(){
    printf("0.666667\n");
    return 0;
}

E Bogo Sort

题目传送门

Bogo Sort

思路

首先对题意进行大致说明,就是将一个数组按照题目给的数组的方式进行置换,也就是置换群的变换
1、求出每个环的长度和环的个数
2、求所有环的lcm,但是很明显爆long long了,所有可以采取高精乘低精的方法,求出所有数字中出现的素数的个数,然后乘起来。

代码

#include
#include
using namespace std;
#define INF 0x3f3f3f3f
// #define TDS_ACM_LOCAL
const int N=1e5 + 9;
int pvis[N], vis[N];
int prime[N], psum;
int n, a[N], loop[N], sum, pm[N], k, len,  ans[N];
void mul(int x){
    for(int i=1;i<=len;i++) ans[i]*=x;
    for(int i=1;i<len;i++)if(ans[i]>9) ans[i+1]+=ans[i]/10,ans[i]%=10;
    while(len<n&&ans[len]>9) ans[len+1]+=ans[len]/10,ans[len++]%=10;
    ans[len+1]=0;
}//高精乘低精

void isprime() //埃氏筛素数打表
{
    pvis[1]=1;
    for(int i=2;i<N;i++){
        if(!pvis[i]) prime[psum++]=i;
        for(int j=i*2; j<N; j+=i)pvis[j]=1;
    }
}
void solve(){   
    isprime();
    cin>>n;
    for(int i=1; i<=n; i++)  cin>>a[i];
    for(int i=1; i<=n; i++){                //求数组中环的个数和每个环的长度
        if(!vis[i]){
            loop[++sum]=1;                  //loop存环的长度,sum为个数
            vis[i]=1;
            for(int j=a[i]; j!=i; j=a[j]){
                loop[sum]++;
                vis[j]=1;
            }
        }
    }
    for(int i=1; i<=sum; i++){              //求得所有环长包含的素数的个数的最大值
        for(int j=0; j<psum && loop[i]>1; j++){
            k=0;
            while(loop[i]%prime[j]==0)  loop[i]/=prime[j], k++;
            pm[prime[j]]=max(pm[prime[j]], k);      //pm存出现的素数的最大个数
        }
    }
    len=1, ans[1]=1;        //高精乘低精的准备工作
    for(int i=0; i<psum; i++)    while(pm[prime[i]]--)   mul(prime[i]);
    for(int i=len; i>=1; i--)   cout<<ans[i];   //倒序输出
    cout<<endl;
    return ;
}

int main(){
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
#ifdef TDS_ACM_LOCAL
    freopen("D:\\VS code\\.vscode\\testall\\in.txt", "r", stdin);
    freopen("D:\\VS code\\.vscode\\testall\\out.txt", "w", stdout);
#endif
    solve();
    return 0;
}

D Drop Voicing(LIS)

题目传送门

Drop Voicing

思路

1、第一种操作将倒数第二个移到最前面,花费1
2、第二种操作将第一个移到最后面,花费0
我们可以将这整个序列视作一个头尾相连的环
很明显的我们可以使用2操作到达任何位置,但其不能对环的顺序造成影响
因为操作二可以到达任意位置,所以操作一可以将任意位置数放在任意位置,对环顺序有有影响但花费1
为了使得花费尽可能的小,所以我们应该尽可能的找到一个升序排列尽可能多的数(最长上升子序列LIS)
求得最大LIS的长度后,剩下的数字即为需要改变的,即为最小花费

代码

#include
#include
#include
using namespace std;
const double pi = acos(-1.0);
#define INF 0x3f3f3f3f
// #define TDS_ACM_LOCAL
const int N=1e3 +9;
int f[N];
int n, a[N], ans;
int Lis(int l,int r)
{
	int ans=0;
	f[++ans]=a[l];
	for(int i=l+1;i<=r;i++)
	{
		if(a[i]>f[ans])
		{
			f[++ans]=a[i];
			continue;
		}
		int pos=lower_bound(f+1,f+1+ans,a[i])-f;
		f[pos]=a[i];
	}
	return ans;
}
void solve(){
    cin>>n;
    for(int i=1; i<=n; i++){
        cin>>a[i];
        a[i+n]=a[i];
    }
    for(int i=1; i<=n; i++) ans=max(ans, Lis(i, i+n-1));
    cout<<n-ans<<endl;
    return ;
}

int main(){
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
#ifdef TDS_ACM_LOCAL
    freopen("D:\\VS code\\.vscode\\testall\\in.txt", "r", stdin);
    freopen("D:\\VS code\\.vscode\\testall\\out.txt", "w", stdout);
#endif
    solve();
    return 0;
}

你可能感兴趣的:(2020牛客多校,算法)