DEFI
D. Drop Voicing
题意:
给你一个数列,你可以进行两种操作。
Drop-2: 将n-1位置的数移到第一个位置,变成 pn−1, p1, p2, …, pn−3, pn−2, pn。
Invert: 将第一个数移动到最后一个位置,变成 p2, …, pn−3, pn−2, pn−1,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,所以一定不会大于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==maxidi 的话,就要在中间那行的 '|' 前边输出一个 ‘*’ 。
题解
记得开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;
} 
京公网安备 11010502036488号