思路:
- 可以从小到大排序,设当前已经有cnt人说了真话(初始为0),如果至少a[i]人说假话是小于等于n-cnt的,我们就可以认为他说的真话。cnt++
- 最后判断说真话的人中最大的a[i]是不是小于n-cnt,是则是情况符合,否则,这个被归为真话的人说的是假话,矛盾
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
const int N = 2e5 + 10;
int a[N];
void mysolve()
{
int n;
cin>>n;
for(int i=1; i<=n; ++i)cin>>a[i];
sort(a+1,a+1+n);
int cnt=0,p=-1;
for(int i=1; i<=n; ++i)
{
if(a[i]==p)cnt++;
else
{
if(n-cnt>=a[i])cnt++,p=a[i];//记录真话
else break;
}
}
if(n-cnt>=p)cout<<n-cnt<<endl;
else cout<<-1<<endl;
}
int32_t main()
{
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll t=1;
cin >> t;
while (t--)
{
mysolve();
}
system("pause");
return 0;
}
思路:
- 把公式拆开就是(b[1]+l +b[2] +b[3]-r),显然我们可以预处理前缀与后缀的最大值,枚举每个b[2],然后求最大值
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
const int INF = 0x3f3f3f3f; //int型的INF
const int N = 2e5 + 10;
int a[N],l[N],r[N];
void mysolve()
{
int n;
cin>>n;
for(int i=1; i<=n; ++i)cin>>a[i],l[i]=max(l[i-1],a[i]+i);
r[n+1]=-INF;
for(int i=n; i>=1; --i)r[i]=max(r[i+1],a[i]-i);//预处理前后缀最大值
int ans=-INF;
for(int i=2; i<n; ++i)ans=max(ans,a[i]+l[i-1]+r[i+1]);
cout<<ans<<endl;
}
int32_t main()
{
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll t=1;
cin >> t;
while (t--)
{
mysolve();
}
system("pause");
return 0;
}
思路:
- 如果我们知道拓扑序,那显然就是对拓扑序dp遍可获得答案了。
- 那么如何获得拓扑序呢,可以状态压缩,我们可以初始每个模特在每个城市都是值比别人大。
- 之后枚举每个城市,该模特对于其他人,比如i,只要在任意城市中有一个城市是值比模特i的值小。不符合,与上0。(否则与上1,就是没变化)。i个城市枚举后就可以获得每个人比别人大的bitset
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
#define int long long
const int N = 5e3 + 10;
void mysolve()
{
int n,m;
cin>>n>>m;
vector<int>p(m);
vector<vector<int>>a(n,vector<int>(m));
for(int i=0; i<m; ++i)cin>>p[i];
for(int i=0; i<n; ++i)for(int j=0; j<m; ++j)cin>>a[i][j];
vector<bitset<N>>bs(m);
for(int i=0; i<m; ++i)bs[i].set();//初始都是比其他人大,都为1
for(int i=0; i<n; ++i)//枚举每个城市
{
vector<int>id(m);
for(int j=0; j<m; ++j)id[j]=j;
sort(id.begin(),id.end(),[&](int x,int y)//按照当前城市的值给每个模特排序
{
return a[i][x]<a[i][y];
});
bitset<N>tmp;//记录那些比当前j值小的模特
for(int j=0; j<m; ++j)
{
int k=j;
while(k<m-1&&a[i][id[k]]==a[i][id[k+1]])k++;
for(int t=j; t<=k; ++t)bs[id[t]]&=tmp;//显然,在该城市中,j只比tmp中为1的模特值大,所以&tmp(这个影响是永久的)
for(int t=j; t<=k; ++t)tmp.set(id[t]);
j=k;
}
}
vector<int>dp(m);
vector<int>id(m);
for(int j=0; j<m; ++j)id[j]=j;
sort(id.begin(),id.end(),[&](int x,int y)//可以取任意城市的值来排序获得没有比别人大的点,以他为起点进行dp
{
return a[0][x]<a[0][y];
});
for(auto v:id)
{
dp[v]=p[v];
for(int i=0; i<m; ++i)if(bs[v][i])//枚举比他一直比他小的模特
{
dp[v]=max(dp[v],dp[i]+p[v]);
}
}
cout<<*max_element(dp.begin(),dp.end())<<endl;
}
int32_t main()
{
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll t=1;
//cin >> t;
while (t--)
{
mysolve();
}
system("pause");
return 0;
}