NOIP模拟赛2019.8.26题解

T1 死宅与陷阱

在这里插入图片描述
用DFS预处理出每个节点被走道的概率(注意每个节点可能会被多条路到达)

然后sort排序,贪心把炸弹放到除起点外概率最高的的点。

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100005;
int n,m,p,s,t,head[N],tot=0,a[N],cnt=0,v[N];
double ans=0,val[N];
struct edge{
	int ver,to;
	double v;
}e[N];
int read(){
	int sum=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return sum*f;
}
void print(int x){
	if(x<0){putchar('-');x=-x;}
	if(x>9)print(x/10);
	putchar(x%10+'0');
}
void add(int x,int y,double z){
	e[++tot].ver=y;
	e[tot].v=z;
	e[tot].to=head[x];
	head[x]=tot;
}
void dfs(int x,double now){
	for(int i=head[x];i;i=e[i].to)
	{  
	    int y=e[i].ver; 
		val[y]+=now*e[i].v;
		ans+=a[y]*now*e[i].v;
		dfs(y,e[i].v*now);
	}
}
bool comp(double x,double y){
	return x>y;
}
int main(){
//	freopen("trap.in","r",stdin);
//	freopen("trap.out","w",stdout);
	n=read();m=read();p=read();s=read();t=read();
    for(int i=1;i<=n;i++)
    a[i]=read();
    int x,y;double z;
    for(int i=1;i<=m;i++)
    {
    x=read();y=read();
    scanf("%lf",&z);
    add(x,y,z);
	}
	ans+=a[s]*1.0;
    dfs(s,1); 
    sort(val+1,val+n+1,comp);
    for(int i=1;i<=t;i++)
    {
    ans+=p*val[i];
    }
    printf("%.3lf",ans);
	return 0;
} 

T2 抗议

在这里插入图片描述

f[i]:前j个奶牛分组的方案数

sum[i]:前i个奶牛的前缀和

朴素DP:当sun[j]<sum[i] f[i]+=f[j] (j<i)

若能转移,j的前缀和要小于等于i的前缀和(j+1~i区间和为非负)

直接做会超时,只有80pts

所以可以离散化后用树状树组维护前缀和

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100005,mod=1000000009;
int n,cnt;
ll ans,t[N];
struct st{
	int id,num;
	ll sum;
}a[N];
ll read(){
	ll sum=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return sum*f;
}
void print(ll x){
	if(x<0){putchar('-');x=-x;}
	if(x>9)print(x/10);
	putchar(x%10+'0');
}
bool comp1(st a,st b){
	return a.sum<b.sum;
}
bool comp2(st a,st b){
	return a.id<b.id;
}
int lowbit(int x)
{
	return x&(-x);
}
int ask(int x)
{
	int ans=0;
    while(x)
	{
	    ans=(ans+t[x])%mod;
		x-=lowbit(x);	
	}
	return ans;
}
void add(int x,int val)
{
    while(x<=cnt)
	{
		t[x]=(t[x]+val)%mod;
		x+=lowbit(x);
	}
}
int main(){
//	freopen("protest.in","r",stdin);
//	freopen("protest.out","w",stdout);
     n=read();
	for(int i=1;i<=n;i++)
    { 
      a[i].sum=read();
      a[i].sum+=a[i-1].sum;
      a[i].id=i;
    } 
     sort(a,a+n+1,comp1);
     cnt=1;
     a[0].num=1;
     for(int i=1;i<=n;i++)
     if(a[i].sum==a[i-1].sum)a[i].num=cnt;
     else a[i].num=++cnt;
     sort(a,a+n+1,comp2);   
	 add(a[0].num,1);
	 for(int i=1;i<=n;i++)
	 {
	  ans=ask(a[i].num)%mod;
	  add(a[i].num,ans);
	 }
	 print(ans);
	 return 0;
} 

T3 蒲公英的约定

在这里插入图片描述
在这里插入图片描述
本来以为是BSGS,结果只有40分orz

但观察可得,答案是可以通过最后倒推得到的。

最后要使异或值为0,那lastans=c

因为lastans=b ^ c 所以b=lastans^ c 所以我们倒着异或,就可以得到每个x,再快速幂,得到每个b

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100005;
int a[N],c[N],ans[N],tot=0,b,x,p; 
int read(){
	int sum=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return sum*f;
}
int pow(int a,int b)
{
	int sum=1;
	while(b>0)
	{
		if(b&1)sum=(ll)sum*a%p;
		a=(ll)a*a%p;
		b>>=1;
	}
	return sum;
} 
int main(){
//	freopen("dandelion.in","r",stdin);
//	freopen("dandelion.out","w",stdout);
    p=read();
    tot=0;
    while(cin>>a[++tot])cin>>c[tot]; 
    tot--;
    x=c[tot];
    for(int i=tot-1;i>=1;i--){
    	ans[i]=x;
    	b=pow(a[i],x);
    	x=c[i]^b;
	}
	for(int i=1;i<tot;i++)
	printf("%d\n",ans[i]);
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值