首页 > 其他分享 >9.21-CSP-S模拟8

9.21-CSP-S模拟8

时间:2022-09-21 21:22:06浏览次数:61  
标签:9.21 int Rep typedef long maxn CSP 模拟 define

T1 JOI 2022 Final T3「選挙で勝とう / Let's Win the Election」

赛时对着一个假贪心不知道为什么是错的。

贪心就是枚举选几个协作州,然后贪心把小的都拿了,剩下的支持州挑小的。
可能会出现某个协作州的 \(b\) 小,但是 \(a\) 更小,导致将他与某个支持州交换反而更优。

于是需要dp,考虑我们要选出 \(p\) 个支持州,设 \(f_{i,j}\) 表示在前 \(i\) 个州里,选出 \(j\) 个协作州的最小时间,我们发现前 \(i\) 个州是不可能不选的,要么是协作州,要么是支持州。因为如果有一个州没选,那么我把其后选的一个协作州换成它显然更优。于是还是枚举协作州的数量,然后做一次dp,统计答案时枚举最后一个协作州是谁,然后从它之后的州里贪心的选 \(a\) 小的即可。

点击查看代码


#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;

const int maxn=5e2+10,INF=1e9;
const double eps=1e-4;


int n,K,mx;

struct Ver{double a,b;}E[maxn];

bool cmp1(const Ver &x,const Ver &y){return x.b<y.b;}
bool cmp2(const Ver &x,const Ver &y){return x.a<y.a;}

double pre[maxn];
double f[maxn][maxn];
double ans=INF;

multiset<double>S,rec;

void Get(int Te){
	Rep(i,0,n)Rep(j,0,n)f[i][j]=INF;
	f[0][0]=0;
	Rep(i,1,K){
		Rep(j,0,min(Te,i)){
			f[i][j]=min(f[i][j],f[i-1][j]+E[i].a/(Te+1));
			if(j>=1 && abs(E[i].b-INF)>eps)f[i][j]=min(f[i][j],f[i-1][j-1]+E[i].b/j);
		}
	}
	S=rec;
	Dwn(i,K,0){
		double te=0;
		//Rep(j,i+1,K)te+=E[j].a;
		auto it = S.begin();
		Rep(j,i+1,K)te+=(*it),++it;
		ans=min(ans,f[i][Te]+te/(Te+1));
		S.insert(E[i].a);
	}
}

void solve(){
	cin>>n>>K;
	Rep(i,1,n){ cin>>E[i].a>>E[i].b; if(E[i].b==-1)E[i].b=INF;else ++mx; } 
	sort(E+1,E+n+1,cmp1);
	Rep(i,K+1,n)rec.insert(E[i].a);
	Rep(i,0,min(K-1,mx))Get(i);
	cout<<fixed<<setprecision(10)<<ans<<"\n";
}

int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }


T2 JOISC 2017 Day1 T2「港湾設備 / Port Facility」

其实并查集做是很容易想的,即时删点保证连边复杂度也是很容易想的,零分也是很容易拿的

因为即时删点的并查集做法是没有办法把边连全的,所以根本判不了无解,如果题目保证有解的话就比较美妙了。

正解就是不删点,而是维护联通块,然后维护nxt指针指向下一个联通块,连边后就把他们合并起来,然后在图上贪心做染色就能判无解

T3 JOISC 2017 Day3 T2「細長い屋敷 / Long Mansion」

考虑暴力扩展的做法,把当前拥有的钥匙用某种东西维护起来显然是劣的,考虑优化我们判断能不能开一个门的方法。

假设我从 \(x\) 点开始扩展,当前已经扩展到的区间为 \([l,r]\),如果我们想要扩展到 \(r+1\),那么 \([l,r]\) 内至少有一个屋子里有 \(c_{r+1}\),因为我从左向右走,只要离 \(r+1\) 最近的出现了 \(c_{r+1}\) 的位置已经被扩展到即可,于是我们只需要维护一个 \(L_i\) 表示 \(c_i\) 在之前的最近一次出现的位置。向 \(l-1\) 扩展同理。

暴力扩展每一个点是 \(n^2\) 的,考虑优化它。假设我们现在已经扩展完了一个点,正在扩展的另一个点此时扩展到了它,那么这个点所有能到的位置正在扩展的点一定都能到,于是我们可以直接对两者的答案取并集给当前扩展的点。这样进行类似记忆化搜索,每次我要扩展一侧边界时,就从那个边界开始做一次扩展,然后取并集即可,如果已经扩展过了就直接返回跑路。

复杂度 \(O(n)\),实测比随机化快一点

点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;

const int maxn=5e5+10;

int n,q;
int c[maxn];
vector<int>vec[maxn];
int last[maxn];
int L[maxn],R[maxn],p[maxn];
bool vis[maxn];
pii rg[maxn];

void Sol(int x){
	bool flag=false;
	if(vis[x])return void();
	if(rg[x].fir>0)return;
	vis[x]=true;
	int &l =rg[x].fir,&r=rg[x].sec;
	l=x,r=x;flag=true;
	while(flag){
		flag=false;
		if(l>1 && R[l-1]>=l && R[l-1]<=r)
		{ Sol(l-1);flag=true; l=min(l,rg[l-1].fir),r=max(r,rg[l-1].sec); }
		if(r<n && L[r]<=r && L[r]>=l)
		{ Sol(r+1);flag=true; l=min(l,rg[r+1].fir),r=max(r,rg[r+1].sec); }
	}
}

void solve(){
	cin>>n;int x,y;
	for(int i=1;i<n;++i)cin>>c[i];
	Rep(i,1,n){
		cin>>y; Rep(j,1,y){ cin>>x;vec[i].push_back(x);last[x]=i; }
		if(i!=n)L[i]=last[c[i]];
	}
	Rep(i,1,n)last[i]=n+1;
	Dwn(i,n,1){ for(auto it : vec[i])last[it]=i; R[i-1]=last[c[i-1]]; }
	Rep(i,1,n)Sol(i);
	cin>>q;
	while(q--){
		cin>>x>>y;
		if(rg[x].fir<=y && rg[x].sec>=y)cout<<"YES\n";
		else cout<<"NO\n";
	}
}

int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }


T4 JOISC 2017 Day3 T1「長距離バス / Long Distance Coach」

发现几个性质

  • 每次下车的都是一段后缀
  • 如果某个人会下车,那么一定尽早下
  • 水的价格是相同的,于是可以每次到服务站时水箱都是空的
  • 如果一个人作为被删的后缀的末尾,那么它某次喝水的时间一定与下一个服务站到达的时间相邻(中间没有其他人要喝水)

于是我们可以按照一个 \(T\) 内喝水的时间对乘客排序,逐个考虑其是否下车。设 \(f_i\) 表示前 \(i\) 个人的最小费用

如果不下车

\[f_i=f_{i-1}+W \times (\lfloor \frac{X}{T} \rfloor+ D_i \leq X \bmod T) \]

如果下车

\[f_i=\min_{1\leq j < i} f_j+pre_i-pre_j+W \times mt_i \times (i-j) \]

\(pre_i\) 为前 \(i\) 个人退费的和,\(mt_i\) 为第 \(i\) 个人最少在喝几次水后下车。\(mt\) 可以把所有服务站出现的时间对周期取模后排序,单指针扫一遍处理。

由于司机一定不能下车,每个点只能从比靠前的转移,转移不会成环。下车的转移是套路的斜率优化。

点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
#define int ll
using namespace std;

const int maxn=2e5+10,INF=1e18;

int X,n,m,W,T;

int s[maxn];
struct Per{
	int D,C,mini;
	bool operator<(const Per &rhs)const{ return D<rhs.D; }
}E[maxn];

int f[maxn];
int pre[maxn];
pii t[maxn];

int q[maxn],top;

#define S(x) (f[x]-pre[x]) 

int Query(int x){
	int l=1,r=top+1;
	while(r-l>1){
		int mid=(l+r)>>1;
		if(x*(q[mid]-q[mid-1])>(S(q[mid])-S(q[mid-1])))l=mid;
		else r=mid;
	}
	return q[l];
}

void solve(){
	cin>>X>>n>>m>>W>>T;
	Rep(i,1,n)cin>>s[i],t[i]=mair(s[i]%T,s[i]);
	t[++n]=mair(X%T,X);
	Rep(i,1,m)cin>>E[i].D>>E[i].C,E[i].mini=INF;
	sort(E+1,E+m+1);sort(t+1,t+n+1);
	E[m+1].D=T;
	int p=1;
	Rep(i,1,m){
		while(p<=n && t[p].fir<E[i].D)++p;
		while(p<=n && t[p].fir<E[i+1].D)E[i].mini=min(E[i].mini,t[p++].sec/T);
		pre[i]=pre[i-1]+E[i].C;
	}
	++top;
	Rep(i,1,m){
		f[i]=f[i-1]+W*((X/T)+(X%T>=E[i].D ? 1 : 0));
		if(E[i].mini<INF){ int j=Query(W*E[i].mini); f[i]=min(f[i],f[j]+pre[i]-pre[j]+W*E[i].mini*(i-j)); }
		while(top>1 && (S(x)-S(q[top]))*(q[top]-q[top-1])<=(S(q[top])-S(q[top-1]))*(x-q[top]))--top;
		q[++top]=x;
	}
	cout<<f[m]+(X/T+1)*W<<"\n";
}

#undef int 
int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }

标签:9.21,int,Rep,typedef,long,maxn,CSP,模拟,define
From: https://www.cnblogs.com/Delov/p/16717171.html

相关文章

  • 20220921 模拟赛
    T1彩票\(n\leq10^5\)。发现三等奖有三种情况,一等奖和二等奖却都只有一种情况,感觉很烦,考虑暴力做掉三等奖的彩票号码,直接三重循环枚举,这一部分消耗\(O(\dfrac{100^3......
  • CSP 2021
    普及分糖果(红)没有1A,身败名裂)点击查看代码#include<bits/stdc++.h>#definefffflush(stdout)#definethankputs("感恩......
  • 9.21Leetcode记录
    一、数据流中的中位数题目如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那......
  • 模拟spotlight
     实现方式:将聚光灯颜色按与光源的距离叠加到光照模型上,阴影用shadowmap:在光源处放一个相机,生成一张深度图和转换矩阵,再用主相机渲染出的片元的深度余存储的深度相比,小于......
  • CSP-S2022游记
    2022.9.18晚分数估出来了,63.5,比去年高(去年才三十几分啊/(ㄒoㄒ)/~),一部分原因是我的成长,还有一部分是因为确实比去年简单不少。单论分数我满意,一比较又觉得担心且不甘心。......
  • 9.21课上问题与思考
    在本周的Java课上我获得了以下的思考与感受一、懒人造就了方法对于相同的开山一事,愚公和李冰有不同的方式去处理。愚公选择一点点去凿山,靠日积月累的努力去完成目标,李冰......
  • 【学习随笔】2022.9.21
     ①左扰动与右扰动的添加规则:          #参考链接①为什么要使用齐次坐标②三维空间刚体的旋转③李群与李代数浅讲......
  • 31. [实例]Cookie模拟登录
    1.前言在使用爬虫采集数据的规程中,我们会遇到许多不同类型的网站,比如一些网站需要用户登录后才允许查看相关内容,如果遇到这种类型的网站,又应该如何编写爬虫程序呢?Cookie......
  • 9.20 模拟赛总结
    又挂分,乐。作业多,少写几句。T1基础dp,T2tarjan板子,T3大模拟。T1写完过不去样例,调了半小时,一共没几行的代码写出了不下五处错,谔谔。T2写完(看上去)没有什么锅。T3......
  • CSP-j/s 2022 第一轮(初赛)游记
    CSP-J/S2022第一轮游记HA(河南)省今年cspj报名人数较去年增长66%……挺离谱的eee由于没有疫情,初赛定在了线下举办,似乎今年pj要卡掉\(1e3\)个人左右CwC一些文中的名词......