【比赛报告】2018.10.15校赛[2015-9-13 NOIP模拟赛 by hzwer] NOIP练习赛卷十四

比赛时间:2018.10.15 选手:lrllrl 用时:2h 得分:100+10+90=200


在这里插入图片描述
在这里插入图片描述
最初想法是一个背包问题。首先背包问题的模型肯定是不行的,但是我们可以列出状态转移方程后发现,每个状态决策会对它之后的决策产生后效性。所以我们就倒着来考虑。考虑最终的结果会是怎么求出来的(假设只有 a a a b b b 同理):
a n s = ( w × a i 1 + w × Δ k × a i 2 + ⋯ + w × Δ k m − 1 × a i m ) ans=(w\times a_{i_1}+w\times\Delta k\times a_{i_2}+\cdots+w\times\Delta k^{m-1}\times a_{i_m}) ans=(w×ai1+w×Δk×ai2++w×Δkm1×aim)
变形为我们倒序的情况:
a n s = w × ( Δ k m − 1 × a i m + ⋯ + Δ k × a i 2 + a i 1 ) ans=w\times(\Delta k^{m-1}\times a_{i_m}+\cdots+\Delta k\times a_{i_2}+a_{i_1}) ans=w×(Δkm1×aim++Δk×ai2+ai1)
我们发现这样没走一步对后面没有影响,所以尽量让当前最大就行了。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int n,k,c,w,x[N],type[N];
double deltak,deltac,ans=0;
int main()
{
	//freopen("explo.in","r",stdin);
	//freopen("explo.out","w",stdout);
    scanf("%d%d%d%d",&n,&k,&c,&w);
    deltak=1.0-0.01*k;
    deltac=1.0+0.01*c;
    for(int i=1;i<=n;i++)
        scanf("%d%d",&type[i],&x[i]);
    for(int i=n;i;i--)
        if(type[i]==1)ans=max(ans,ans*deltak+x[i]);
        else ans=max(ans,ans*deltac-x[i]);
    printf("%.2f\n",ans*w);
    return 0;
}

在这里插入图片描述
在这里插入图片描述
根据抽屉原理,当询问区间长度大于 p p p 的时候一定存在一段子区间的和能被 p p p 整除的情况。
考虑小于 p p p 的长度,我们记录前缀和,O(n)扫描前缀和的同时查找曾经出现过的与其最相近的前缀和。作差取最小值。
正解是写treap或splay或替罪羊树啥的,我这里set居然过了也是神奇。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
const int N=5e5+10;
typedef long long ll;
const ll INF=0x7fffffff;
template<class T>inline void read(T&x)
{
	x=0;int f=0;char ch=getchar();
	while(ch<'0'||ch>'9')f|=ch=='-',ch=getchar();
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    if(f)x=-x;
}
int n,m,l,r,p,a[N];
ll sum[N];
int main()
{
	//freopen("in.txt","r",stdin);
    read(n);read(m);
    for(int i=1;i<=n;i++)
        read(a[i]),sum[i]=sum[i-1]+a[i];
    while(m--)
    {
    	read(l);read(r);read(p);int ans=p;
    	if(r-l+1>=p){puts("0");continue;}
    	set<int>s;s.clear();s.insert(0);
    	for(int i=l;i<=r;i++)
    	{
			int tmp=(sum[i]-sum[l-1])%p;
			set<int>::iterator it=s.upper_bound(tmp);
    		if(it!=s.begin())it--;
    		ans=min(ans,tmp-*it);
    		s.insert(tmp);
		}
		printf("%d\n",ans);
	}
	return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这题居然是T3,让人感到惊奇,一看就是个二分+spfa。准备就这么过掉时突然想到一种情况,如果一个负环与 n n n 点不连通,可能会花费许多无用的值去使它变成非负环。于是先建反图深搜一遍打个标记再建图二分跑spfa。(于是我判断1号点是否连通写错了,90分qwq)

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=110,M=1e5+10;
int n,m,hd[N],vis[N],tot,t,cnt[N],avl[N];
ll dis[N],ans;
struct Edge{
	int v,w,nx;
}e[M];
struct edge{
	int u,v,w;
}tmp[M];
void add(int u,int v,int w)
{
	e[++tot].v=v;
	e[tot].w=w;
	e[tot].nx=hd[u];
	hd[u]=tot;
}
ll spfa(int mid)
{
	memset(vis,0,sizeof(vis));
	memset(dis,0x3f,sizeof(dis));
	memset(cnt,0,sizeof(cnt));
	queue<ll>q;while(q.size())q.pop();
	q.push(1);vis[1]=1;dis[1]=0;
	while(q.size())
	{
		int u=q.front();q.pop();vis[u]=0;
		for(int i=hd[u];i;i=e[i].nx)
		{
			int v=e[i].v;if(!avl[v])continue;
			if(dis[v]>dis[u]+e[i].w+mid)
			{
				dis[v]=dis[u]+e[i].w+mid;
				if(!vis[v])
				{
					q.push(v);
					if(++cnt[v]>=n)return -0x3f3f3f3f;
				}
			}
		}
	}
	return dis[n];
}
void dfs(int u){avl[u]=1;for(int i=hd[u];i;i=e[i].nx)if(!avl[e[i].v])dfs(e[i].v);}
int main()
{
	//freopen("earth.in","r",stdin);
	//freopen("earth.out","w",stdout);
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		memset(hd,0,sizeof(hd));tot=0;
		memset(avl,0,sizeof(avl));
		for(int i=1;i<=m;i++)
		    scanf("%d%d%d",&tmp[i].u,&tmp[i].v,&tmp[i].w);
		for(int i=1;i<=m;i++)
		    add(tmp[i].v,tmp[i].u,tmp[i].w);
		dfs(n);
		memset(hd,0,sizeof(hd));tot=0;
		for(int i=1;i<=m;i++)
		    add(tmp[i].u,tmp[i].v,tmp[i].w);
		int l=-100000,r=100000,mid;
		if(!avl[1]){printf("-1\n");continue;}
		while(l<=r)
		{
			int mid=(l+r)/2;ll dist=spfa(mid);
			if(dist>=0)ans=dist,r=mid-1;
			else l=mid+1;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

赛后总结

问题有很多:
1.T1没有很快的反应过来倒序消除后效性再贪心的每步去最大值,足足浪费50分钟。
2.T2的暴力居然只打了十分。而且没有想到可以固定左端点二分右端点,思路没有打开,没想清楚根据前缀和作差可以考虑到任何一个子区间。只要想到这点,即便甩个set上去也能AC
3.T3的判断连通瞎姬霸写,又丢掉10分。
分就是这样一点一点扣下去的,扣着扣着就是1=—>2=。吸取教训。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值