题目大意:
你有n本书,每本书有自己的序号,阅读规则是:从编号为1的书开始阅读,只能连续的阅读下去,也就是从1,2,3…等到 i , 同时你可以把自己未阅读的两本书换成一本任意编号的书,求你最多能读几本书。
思路:很明显二分答案即可,因为答案具有单调性。注意怎么统计即可。
code:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
const int N=3e5+10;
const double eps=1e-4;
map<int,int> mp;
int a[N];
int n;
int get(int x)
{
int ans=0,sum=0;
for(auto v:mp){
int aa=v.first,bb=v.second;
if(aa<=x){
ans++;
sum+=bb-1;
}
else sum+=bb;
}
return ans+sum/2;
}
void work()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],mp[a[i]]++;
int l=n/2,r=n;
while(l<r)
{
int mid=l+r+1>>1;
if(get(mid)<mid) r=mid-1;
else l=mid;
}
cout<<r<<endl;
}
signed main()
{
int t;
//cin>>t;
t=1;
while(t--)
{
work();
}
return 0;
}
D
题目大意:
有n张牌,第 i 张牌正面和反面分别写有数字
a
i
a_i
ai 和
b
i
b_i
bi ,给定一个数值K,问这些牌的值加起来能否恰好等于K,每张牌可以使用正面的数字也可以使用反面数字。
如果可以,则输出每张牌的状态。
思路:很明显的dp问题,有点类似于背包,f[i][j]表示是否前 i 个数能恰好凑成 j 。
具体的转移方程为 :
if(f[i][j]) //如果f[i][j]能凑成,则
if(j+a[i+1]<=s) f[i+1][j+a[i+1]]=1;
if(j+b[i+1]<=s) f[i+1][j+b[i+1]]=1;
同时这道题还需要记录路径,注意一下如何记录和输出路径,其实就是倒着做状态转移。
code:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
const int N=1e2+10,M=1e4+10;
const double eps=1e-4;
int f[N][M],a[N],b[N];
int n;
int st[N];
vector<char> ans;
void work()
{
int n,s;
cin>>n>>s;
for(int i=0;i<=n;i++){
for(int j=0;j<=s;j++) f[i][j]=0;
}
for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
f[0][0]=1;
for(int i=0;i<n;i++){
for(int j=0;j<=s;j++){
if(f[i][j]) {
if(j+a[i+1]<=s) f[i+1][j+a[i+1]]=1;
if(j+b[i+1]<=s) f[i+1][j+b[i+1]]=1;
}
}
}
if(f[n][s]) {
cout<<"Yes"<<endl;
for(int i=n;i>=1;i--){
if(s>=a[i]&&f[i-1][s-a[i]]) {
s-=a[i]; ans.push_back('H');
}
else {
s-=b[i]; ans.push_back('T');
}
}
reverse(ans.begin(),ans.end());
for(auto i:ans) cout<<i;
}
else cout<<"No"<<endl;
}
signed main()
{
int t;
//cin>>t;
t=1;
while(t--)
{
work();
}
return 0;
}
E
题目大意:给定m条路,给定一个序列E,求从点1到n的最短路,同时要满足选的道路的编号要时E的一个子序列。
思路: 可以发现可以直接在序列E上做dp,因为要满足选的编号是其子序列,有点类似拓扑排序。
dp[i]表示1到 i 的最短路。
转移为:
f[v[i]]=min(f[v[i]],f[u[i]],+w[i])
code:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define x first
#define y second
const int N=3e5+10;
const double eps=1e-4;
typedef pair<int,int> pii;
int f[N];
int a[N],b[N],c[N];
void work()
{
int n,m,k;
cin>>n>>m>>k;
for(int i=1;i<=n;i++) f[i]=1e18;
f[1]=0;
for(int i=1;i<=m;i++) cin>>a[i]>>b[i]>>c[i];
for(int i=1;i<=k;i++){
int x; cin>>x;
f[b[x]]=min(f[b[x]],f[a[x]]+c[x]);
}
if(f[n]==1e18) cout<<-1<<endl;
else cout<<f[n]<<endl;
}
signed main()
{
int t;
//cin>>t;
t=1;
while(t--)
{
work();
}
return 0;
}