首页 > 其他分享 >9.3 noip 模拟赛 1 题解

9.3 noip 模拟赛 1 题解

时间:2022-09-03 21:46:21浏览次数:92  
标签:const noip int 题解 dis 1ll inline 9.3 mod

noip 模拟赛 1 题解

目录

\(\to link \leftarrow\)

A 一步之遥

构造题

手玩了一下没有什么好的想法

后来在想能不能用递推的方式处理,也就是知道 \(N\) 的答案如何推导出 \(N+1\) 的答案

容易发现,\(N\) 的排列 \(\to\) \(N+1\) 的排列只是多了一个数而已,而我把多出来的数按顺序插入原排列的缝隙里就可以得到新的 \(N+1\) 种排列

计算一下,原来总共有 \(N!\) 种,现在每个排列都有新的 \(N+1\) 种排列,共是 \((N+1)!\) 种,刚好处理完

但是有一个小细节:

在一次按从左往右顺序插入后显然被插入的到了最右侧,那么就需要改变顺序为从右往左

这样就可以完成此题

时间复杂度:$$O(\sum_{i=1}^N i!)$$

#include<bits/stdc++.h>
using namespace std;

struct node{
	int A[10];
};

vector <node> p[10];

int n,a[10];

inline void print(node x){
    for(int i=1;i<=n;++i) cout<<x.A[i]<<" ";
    cout<<endl;
}

inline void solve(int x){
	node t;
	int cnt=0;
	for(node y:p[x-1]){
		if(!cnt){
			t.A[1]=1;
			for(int i=2;i<=x;++i) t.A[i]=y.A[i-1]+1;
			p[x].push_back(t);
			for(int i=2;i<=x;++i){
				swap(t.A[i],t.A[i-1]);
				p[x].push_back(t);
			}
		}
		else{
			t.A[x]=1;
			for(int i=1;i<x;++i) t.A[i]=y.A[i]+1;
			p[x].push_back(t);
			for(int i=x-1;i;--i){
				swap(t.A[i],t.A[i+1]);
				p[x].push_back(t);
			}
		}
        cnt^=1;
	}
}

signed main(){
	cin>>n;
	for(int i=1;i<=n;++i) a[i]=i;
	node x;
	x.A[1]=1,x.A[2]=2;
	p[2].push_back(x);
	x.A[1]=2,x.A[2]=1;
	p[2].push_back(x);
	solve(3);
	solve(4);
	solve(5);
	solve(6);
	solve(7);
	solve(8);
	solve(9);
	for(node x:p[n]){
    	print(x);
	}
}

退位计划

说实话我没有怎么做过计数题,考试遇到计数题基本都无了

就是算不明白……

而且容斥原理也用不明白,这一方面有待提高

这题可以转化成一个染色问题

我们假设 \(f_i\) 表示在没有每种颜色至少出现一次的情况下使用至多 \(i\) 种颜色的方案数

那么显然根可以染 \(i\) 种颜色,其余节点不能跟父亲染的一样,只能染 \(i-1\) 种颜色

总方案数 \(f_i=i\times (i-1)^{n-1}\)

根据容斥原理得,答案:

\[ans=\sum_{i=1}^k(-1)^{k-i}\cdot {k\choose i}\cdot f_i \]

时间复杂度 \(O(n+k\log n)\)

#include<bits/stdc++.h>
using namespace std;

const int N=1e6+5;
const int mod=1e9+7;

int n,k,ans;
int frac[N],f[N];

inline int qpow(int x,int idx){
	if(!idx) return 1;
	int t=qpow(x,idx>>1);
	return (idx&1)?1ll*t*t%mod*x%mod:1ll*t*t%mod;
}

inline int C(int x,int y){
    if(x==y) return 1;
	return 1ll*frac[x]*qpow(frac[y],mod-2)%mod*qpow(frac[x-y],mod-2)%mod;
}

signed main(){
	cin>>n>>k;
	frac[1]=1;
	for(int i=2;i<=1000000;++i) frac[i]=1ll*frac[i-1]*i%mod;
	for(int i=1;i<=k;++i)
		f[i]=1ll*i*qpow(i-1,n-1)%mod;
	for(int i=1;i<=k;++i){
        //cout<<qpow(-1,k-i)<<" "<<C(k,i)<<" "<<f[i]<<endl;
		ans=((ans+1ll*qpow(-1,k-i)*C(k,i)%mod*f[i]%mod)%mod+mod)%mod;
	}
	cout<<ans<<endl;
}

退役以后

打了 2h,就挺恶心的。

看到最长等待(在其下单后等待了最长时间)的人最少需要等待的时间了,老二分套路了

那就二分这个时间 \(x\)

由于要按顺序送快递,快递也是按顺序准备好的,无后效性,

而且特殊的点也只有一个 \(1\) 号点 (取快递),想到用 \(dp\)

设 \(f_{i,j,0/1}\) 表示已经送了前 \(i\) 个快递,已经拿了前 \(j\) 个快递,并且当前在 \(u_i\ /\ 1\)号点所需的最小时间

设 \(g_j=\min\{f_{i,i\sim j,1}\}\)

那么 \(dp\) 式子如下:

for(int i=2;i<=K;++i){
        g[i-1]=inf;
		for(int j=i;j<=K;++j){
			if(f[i-1][j][0]+dis[1][a[i].u]-a[i].s<=x)
				f[i][j][1]=min(f[i][j][1],f[i-1][j][0]+dis[1][a[i].u]);
			if(f[i-1][j][1]+dis[a[i-1].u][a[i].u]-a[i].s<=x)
				f[i][j][1]=min(f[i][j][1],f[i-1][j][1]+dis[a[i-1].u][a[i].u]);
			g[j]=min(g[j-1],f[i][j][1]);
			if(j>i) f[i][j][0]=min(f[i][j][0],max(g[j]+dis[a[i].u][1],1ll*a[j].t));
		}
	}

总时间复杂度:$$O(kNM+K^2\log 1e18)$$ (\(k\) 表示 \(SPFA\) 的常数)

#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define int long long

const int N=1e3+5;
const int M=5e3+5;
const ll inf=1e18;

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

struct work{
	int s,u,t;
}a[N];
struct node{
	int x,v;
};

int n,m,K;
ll dis[N][N],f[N][N][2],g[N];
vector <node> G[N];
bitset <N> vis;

inline void spfa(int s){
	queue <int> q;
	vis.reset();
	for(int i=1;i<=n;++i) dis[s][i]=inf;
	dis[s][s]=0;
	q.push(s);
	vis[s]=1;
	while(!q.empty()){
		int x=q.front();
		q.pop();
		vis[x]=0;
		for(auto y:G[x]){
			if(dis[s][y.x]>dis[s][x]+y.v){
				dis[s][y.x]=dis[s][x]+y.v;
				if(!vis[y.x]){
					vis[y.x]=1;
					q.push(y.x);
				}
			}
		}
	}
}

inline bool check(ll x){
	for(int i=0;i<=K;++i)
		for(int j=0;j<=K;++j)
			f[i][j][0]=f[i][j][1]=inf;
	for(int i=1;i<=K;++i) f[0][i][0]=a[i].t;
	g[0]=inf;
	for(int i=1;i<=K;++i){
		if(f[0][i][0]+dis[1][a[1].u]-a[1].s<=x)
			f[1][i][1]=min(f[0][i][0]+dis[1][a[1].u],f[1][i][1]);
		g[i]=min(g[i-1],f[1][i][1]);
        //cout<<f[1][i][0]<<" "<<g[i]<<endl;
		if(i>1) f[1][i][0]=min(f[1][i][0],max(g[i]+dis[a[1].u][1],1ll*a[i].t));
        //cout<<1<<" "<<i<<" "<<f[1][i][1]<<" "<<f[1][i][0]<<endl;
	}
	for(int i=2;i<=K;++i){
        g[i-1]=inf;
		for(int j=i;j<=K;++j){
			if(f[i-1][j][0]+dis[1][a[i].u]-a[i].s<=x)
				f[i][j][1]=min(f[i][j][1],f[i-1][j][0]+dis[1][a[i].u]);
			if(f[i-1][j][1]+dis[a[i-1].u][a[i].u]-a[i].s<=x)
				f[i][j][1]=min(f[i][j][1],f[i-1][j][1]+dis[a[i-1].u][a[i].u]);
			g[j]=min(g[j-1],f[i][j][1]);
			if(j>i) f[i][j][0]=min(f[i][j][0],max(g[j]+dis[a[i].u][1],1ll*a[j].t));
		}
	}
    //cout<<endl<<endl;
	for(int i=1;i<=K;++i)
		if(f[K][i][1]-a[K].t<=x)
			return 1;
	return 0;
}

signed main(){
	n=read(),m=read();
	while(m--){
		int x=read(),y=read(),z=read();
		G[x].push_back({y,z});
		G[y].push_back({x,z});
	}
	for(int i=1;i<=n;++i)
		spfa(i);
	K=read();
	for(int i=1;i<=K;++i)
		a[i].s=read(),a[i].u=read(),a[i].t=read();
	ll l=-1,r=1e18;
	while(l<r-1){
		ll mid=l+r>>1;
		if(check(mid)) r=mid;
		else l=mid; 
	}
	printf("%lld\n",r);
}

重在参与

标签:const,noip,int,题解,dis,1ll,inline,9.3,mod
From: https://www.cnblogs.com/into-qwq/p/16653139.html

相关文章

  • 洛谷P1850 [NOIP2016 提高组] 换教室(期望dp)
    #include<bits/stdc++.h>usingnamespacestd;intn,m,v,e;intc[3005],d[3005];intf[305][305];doubledp[3005][3005][2];//dp[i][j][k]表示前i步申请更换了j......
  • 9.3
    DataFrame.apply(func,axis=0,broadcast=False,raw=False,reduce=None,args=(),**kwds)该函数最有用的是第一个参数,这个参数是函数,相当于C/C++的函数指针。这个函......
  • ARC146 部分题解
    A普及组题//byBalloons#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#definemprmake_pair#definedebug()cerr<<"Madoka"<<e......
  • P5914 [POI2004]MOS 题解
    题目传送门分析这是一道小学经典的数学题,对于这种求最短时间的题目,我们要认真考虑两组人员:首先,跑的快的人应当跑的最多,能者多劳。其次,跑的慢的人应当跑的最少,否则会拉......
  • CF1389B题解
    题目传送门题目分析首先,这道题比较的简单,是一道较为标准的dp,虽说有大佬说可以用贪心做,但本蒟蒻不会。首先,\(0\leqz\leq\min(5,k)\)所以我们可以开一个二维dp,......
  • 22.9.3 总结
    A求字符串插入多少字符后可以变为回文串。将字符串翻转后与原字符串求最长公共子串。\(ans=\min(i+j-2*f_{i,j}).(i+j=n-(n\mod2))\)code#include<algorithm>#incl......
  • 22.9.3 美团机器学习/数据挖掘岗面试复盘
    昨天参加了美团的机器学习/数据挖掘岗位的面试,和快手的一样,大约持续了一个小时。整体表现很不好,也让我坚定地打消了想要投递大厂的念头。表现不好的原因有多方面的,有因为感......
  • java学习9.3-重写
    1.重写:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作2.应用:重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参数的方法时,实际执行的是子类重写......
  • 信息学一本通 1309:【例1.6】回文数(Noip1999)
    时间限制:1000ms      内存限制:65536KB提交数:17647   通过数:7270【题目描述】若一个数(首位不为零)从左向右读与从右向左读都是一样,我们就将其......
  • 9.3
    这段时间啥都没有记刚开学的几周过得很匆匆当然我也没想到暑假我的复习这么烂拿到工作之前想先工作稳了再读吧拿到工作第一周每天加班,回到宿舍只想打游戏减肥计划也搁......