Sequence Decomposing
1.题意其实就是要我们找共有多少个最长的上升的子序列,也就是理解成可以找到几个尽量长的队伍(最少LIS不相交覆盖)
2.我们开一个multiset,然后先放进去第一个数,由于multiset会对元素自动从小到大排序,那么我们放进的队尾,也是排序好的,然后从第二个数开始遍历,检查一下当前multiset里是否有比这个数小的数,也就是是否有可以接的队伍,如果有我们就更新这个队伍的队尾为当前遍历到的这个数,如果没有呢,只能自己开一个新的队伍了,也就是直接插入这个值,最后multiset的size就是答案,就是有几个队伍
点击查看代码
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int,int> pii;
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};
void solve()
{
int n;
cin>>n;
vector<int>ve(n+1);
multiset<int>se;//对插入的值自动从小到大排序,且可以重复
for(int i=1;i<=n;i++) cin>>ve[i];
se.insert(ve[1]);
for(int i=2;i<=n;i++)
{
auto it=se.lower_bound(ve[i]);//看multiset里面有没有大于该数的,没有it就是ve.end();
if(it==se.begin())//第一个数就大于ve【i】,也就是说ve【i】无法接到任何一个队伍的后面,只能自己插入当队头
{
se.insert(ve[i]);
}else{//可以找到队伍,it为第一个大于等于该值的下标,则it--为第一个小于该数的下标,也就是可以这个数接的队伍
it--;
se.erase(it);//通过删除地址来删除这个值
se.insert(ve[i]);//更新队伍的队尾
}
}
cout<<se.size();
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0);
int t=1;
//cin>>t;
while(t--) solve();
return 0;
}
Dice and Coin
1.拿样例模拟一下,k=3,则1,2,3各占1/3,1要4次变为16大于10,2要3次,3要2次,那么概率就是1/3*(0.54+0.53+0.52)
2.n>k时也不要害怕,大于k的那些数,每个提供的概率就是1/n,枚举计算即可
点击查看代码
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int,int> pii;
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};
void solve()
{
int n,k;
double sum=0;
cin>>n>>k;
for(int i=1;i<=n;i++)
{
int x=i;
double w=1;
while(x<k)
{
x*=2;
w/=2;//相当于若干个1/2相乘
}
sum+=w/n;//每个数字的概率为1/n
}
printf("%.12lf",sum);
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0);
int t=1;
//cin>>t;
while(t--) solve();
return 0;
}
Integer Cards
1.贪心的思想,但是注意代码的实现
2.我们用点的方式来存卡牌数和卡牌值,对数组进行从小到大的排序,对点进行第二个值从大到小的排序,在遍历的时候,用一个变量来实现点的下标移动,检查总和加了这个差值是否比原来的总和大,如果更大则说明使用了这个卡牌,对卡牌数减少1,当点的第一个值为0时,下标++
点击查看代码
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int,int> pii;
#define x first
#define y second
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};
bool cmp(pii a,pii b)
{
return a.y>b.y;
}
void solve()
{
int n,m,sum=0;
cin>>n>>m;
vector<int>ve(n);
for(int i=0;i<n;i++)
{
cin>>ve[i];
sum+=ve[i];
}
pii p[100005];
for(int i=0;i<m;i++)
{
cin>>p[i].x>>p[i].y;
}
sort(all(ve));
sort(p,p+m,cmp);//记得是p+m,而不是p+n
int k=0,sum1=sum;
for(int i=0;i<n;i++)
{
if(p[k].x<=0)//点从大到小排序,当这个较大的值用完以后,下标++
{
k++;
}
sum+=p[k].y-ve[i];
if(sum1<sum) {//如果加完差值后比原来的大说明合理可以转化
sum1=sum;
p[k].x--;//用一次记得减一次
}
else break;//因为点是从大到小排的,数组是从小到大排的,如果当前的点无法满足,后续的点当然也无法满足
}
cout<<sum1;
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0);
int t=1;
//cin>>t;
while(t--) solve();
return 0;
}
equeue
1.先进行区间的枚举,就是两层循环,比如1 2 3 4 5,定住1,然后右区间起点为2 3 4 5,然后左区间变为1 2,右区间起点为3 4 5以此类推下去
2.当左右区间的长度和大于k时,就要cotinue,因为操作次数无法满足
3.枚举后的区间合法以后,我们把区间的放放到一个新的数组里面,先计算这些数当前的总和,然后对数组进行排序,如果有负数,我们就贪心的减掉这个负数,当然对应消耗一次操作数。然后找最大值即可
点击查看代码
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int,int> pii;
#define x first
#define y second
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};
void solve()
{
int n,k,sum=0;
cin>>n>>k;
vector<int>ve(n+1);
for(int i=0;i<n;i++) cin>>ve[i];
for(int l=0;l<n;l++)
{
for(int r=l+1;r<=n;r++)
{
int x=n-r+l+1;//总共有几个数,左右区间长度的和
int cnt=k-x;
if(x>k) continue;//区间长度大于操作次数 不符合题意
vector<int>fi;
int ans=0;
for(int i=0;i<=l;i++) fi.push_back(ve[i]),ans+=ve[i];//注意这里要=l
for(int i=r;i<n;i++) fi.push_back(ve[i]),ans+=ve[i];
sort(all(fi));
//贪心取出负数,排序后越小的负数排前面
for(auto t:fi){
if(cnt==0) break;
if(t<0) {
ans-=t;
cnt--;//操作数记得减1
}
}
sum=max(sum,ans);
}
}
cout<<sum;
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0);
int t=1;
//cin>>t;
while(t--) solve();
return 0;
}
Friendships
1.首先我们画出一个菊花图(n个点),就是中间一个点,周围被n个点包围,然后连接每个点和这个中间点,我们可以发现一个菊花图距离为2的点对数为(n-2)*(n-1)/2
2.然后随机连接每个距离为2的点,这个菊花图的点对数就会-1,先建图就是(1,2),(1,3).....(1,n),这就表示一个菊花图
3.然后我们枚举连接距离为2的点,比如(2,3),(2,4).....画个图出来会更加直观
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define x first
#define y second
typedef pair<int,int> pii;
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};
string s;
signed main()
{
int n,k;
cin>>n>>k;
int p=(n-2)*(n-1)/2;//菊花图的点对数
int cp=p-k;//需要连接的数量
if(cp<0){
cout<<-1;
return 0;
}
vector<pii>ve;
for(int i=2;i<=n;i++) ve.emplace_back(1,i);
for(int i=2;i<=n&&cp;i++) //连接次数够了就行
{
for(int j=i+1;j<=n&&cp;j++)
{
ve.emplace_back(i,j);
cp--;
}
}
cout<<ve.size()<<endl;
for(auto [x,y]:ve) cout<<x<<" "<<y<<endl;
}