传送门 hyflshhl
A、B、E、F比较简单
C、D难一些
A题:注意排序,如果l和r相等,优先删除长度小的;比较简单;
B题:是个很简单的概率DP,注意状态转移;
C题:详解在下面;
D题:详解在下面;
E题:倒序处理一下就好了,有个思路很有趣,就是将字母序看作k进制数,然后从个位加1,进位……实现起来麻烦一些;
F题:可以把序列处理成一个环,切割就是将环切断,把序列处理为两倍的长度等同于环;
A的代码:
#include
#include
#include
#include
using namespace std;
struct hh {int l,r,len;}a[600001];
int n,ans,inf=2147483647;
int calc_r()
{
int cnt=inf;
for(int i=1;i<=n;i++) if(iy.l) return false;
else if(x.len>y.len) return true;
return false;
}
bool cmp2(hh x,hh y)
{
if(x.r>y.r) return true;
else if(x.ry.len) return true;
return false;
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i].l>>a[i].r,a[i].len=a[i].r-a[i].l;
sort(a+1,a+n+1,cmp);
ans=max(calc_r()-calc_l(),calc_r()-calc_l());
sort(a+1,a+n+1,cmp2);
ans=max(ans,calc_r()-calc_l());
if(ans<0) ans=0;
cout<
B的代码:
#include
#include
#include
#include
using namespace std;
int n,n1,n2,I;
double dp[2003][2002],ans,p;
void solve()
{
cin>>n>>n1>>n2>>I>>p;
p/=100;
dp[0][0]=1,dp[1][0]=1-p,dp[1][1]=p;
for(int i=2;i<=n;i++) dp[i][0]=dp[i-1][0]*(1-p);
for(int i=2;i<=I;i++)
for(int j=1;j<=n2 && j<=i;j++)
dp[i][j]=dp[i-1][j-1]*p+dp[i-1][j]*(1-p);
for(int j=0;j<=n2-1;j++) ans+=dp[I-1][j];
printf("%.7lf",ans);
}
int main()
{
solve();
return 0;
}
C的代码:
维护一个堆,记录每个状态(选n个数字)的概率;
每次取最大概率加到答案中,更新下一个状态,即把每行数字的头移向前一个;
cnt.head[i]:在cnt这个状态下,第i行数字头的位置;
#include
#include
#include
#include
#include
using namespace std;
const int MAXN=105;
double ma[MAXN][MAXN];
int n,m,k;
double ans;
struct hh {int head[MAXN];double sum;}cnt;
bool operator < (hh x,hh y) {return x.sum < y.sum;}
priority_queueq;
void solve()
{
cin>>n>>m>>k;
cnt.sum=1.0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
cin>>ma[i][j],ma[i][j]/=100;
sort(ma[i]+1,ma[i]+m+1),cnt.head[i]=m,cnt.sum*=ma[i][m];
}
q.push(cnt);
while(!q.empty() && k)
{
k--;
cnt=q.top(),q.pop();
ans+=cnt.sum;
for(int i=1;i<=n;i++)
{
hh v=cnt;
if(!ma[i][v.head[i]]) continue;
v.head[i]--;
v.sum=(v.sum/ma[i][v.head[i]+1])*ma[i][v.head[i]];
q.push(v);
}
}
printf("%.8lf ",ans);
return;
}
int main()
{
solve();
return 0;
}
D的代码:
参考:https://blog.csdn.net/Code92007/article/details/101350037
两遍Dijkstra处理最短路,记录每个点被最短路经过的次数;
在数组第二维中,0表示以1为起点,1表示以n为起点
dis[i][0/1]:起点到i点的最短路长度;
num[i][0/1]:起点到终点的最短路,以1/n为起点经过i点的次数;
则i点经过的概率为(num[i][1]*num[i][0])/最短路总条数;
注意对于麻花图,可能存在2^100000条最短路;
因此取ln为底,e^a+e^b=e^( a+ln (1+e^(b-a)) )
WA了16次,刚开始是因为没有注意到特殊图的存在;
后来是因为没有开long long?第二次了……
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const ll MAXN=300001;
const ll inf=2e18;
ll fst[MAXN<<1],nxt[MAXN<<1];
ll dis[MAXN][2];
ll n,m,tot;
bool vis[MAXN];
double cnt[MAXN][2];
struct hh {ll f,t;ll c;}ma[MAXN<<1];
struct sh {ll num;ll d;};
bool operator < (sh x,sh y){return x.d>y.d;}
priority_queueq;
void build(ll f,ll t,ll c)
{
ma[++tot]=(hh){f,t,c};
nxt[tot]=fst[f];
fst[f]=tot;
return;
}
double calc(double x,double y)
{
if(xdis[x][st]+ma[i].c)
{
cnt[v][st]=cnt[x][st];
dis[v][st]=dis[x][st]+ma[i].c;
q.push((sh){v,dis[v][st]});
}
else if(dis[v][st]==dis[x][st]+ma[i].c)
cnt[v][st]=calc(cnt[v][st],cnt[x][st]);
}
}
return;
}
void solve()
{
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=m;i++)
{
ll f,t,c;
scanf("%lld%lld%lld",&f,&t,&c);
build(f,t,c),build(t,f,c);
}
Dijkstra(1,0),Dijkstra(n,1);
for(ll i=1;i<=n;i++)
{
double ans=0;
if(dis[i][0]+dis[i][1]==dis[n][0])
ans=exp(cnt[i][0]+cnt[i][1]-cnt[n][0]);
printf("%.8lf ",ans*2.0);
}
return;
}
int main()
{
solve();
return 0;
}
E的代码:
#include
#include
#include
#include
#include
using namespace std;
const int MAXN=200001;
char a[MAXN];
int vis[MAXN];
int n,m;
string s;
int maxx=-1,minn=214748444,cnt;
int f(int x)
{
for(int i=(int)a[x]+1;i<=126;i++)
if(vis[i]) return i;
return 0;
}
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
vis[a[i]]++;
minn=min(minn,(int)a[i]);
}
if(n=1;i--)
{
int flag=f(i);
if(flag)
{
for(int j=1;j<=i-1;j++)
cout<
F的代码:
#include
#include
#include
#include
#include
using namespace std;
string s;
int a[600001];
int ans=-1,cnt,n,last;
void solve()
{
cin>>s;
for(int i=0;i