8.14做题总结

P10701 [SNCPC2024] 致命公司

哭泣天使游戏,你看他他就不动,现在你站在中心 很多个天使在不同时间从不同方向过来,一共n个方向,首先我们把天使出现的时间从大到小排序,对答案进行二分,很明显 要求时间的最大值,答案是单调的,接下来写一个check(time)判断time时间是否可以存活即可

check的逻辑首先开一个标记数组 标记每一个位置当前被看了多少秒,由题目可知 答案和看的顺序是无关的 我们只需要贪心的从大到小遍历所有的点,如果当前情况他能到中心,但是能看的时间还有,就可以放时间去看他,用一个ret记录已经用了多少时间,直到剩下的时间不足当前点的时间 就返回false,不然返回true,注意当天使在check时间之后才出现 可以直接跳过,当该点经过标记以后的值使得他无法到达中心也可跳过

#include<bits/stdc++.h>
using namespace std;
const int N = 5*10e5+1;
#define INF 0x3f3f3f3f3f3f3f3f
struct node{
	 long long t,x,y;
	bool operator <(const node &a){
		return t> a.t;
	}
}h[N];
long long n,m;
 long long k;
 long long bj[N];
bool check(unsigned long long time){
	long long ret=time;
	for(int i = 1;i<=n;i++){
		bj[i]=0;
	}
	for(int i =1;i<=m;i++){
		if(time<h[i].t)continue;
		long long tmp=(h[i].y-1)/k + 1 +bj[h[i].x]+h[i].t-1;
		
		if(tmp>time)continue;
		tmp=time-tmp+1;
		if(ret-tmp+1<h[i].t)return 0;
		ret-=tmp;bj[h[i].x]+=tmp;
}
return 1;
}
int main(){
	ios::sync_with_stdio(false); 
	cin.tie(0); cout.tie(0);
	cin>>n>>m>>k;		
	cin>>h[1].t>>h[1].x>>h[1].y;
	int st=1;
	for(int i = 2;i<=m;i++){
		cin>>h[i].t>>h[i].x>>h[i].y;
		if(h[i].x!=h[i-1].x){
			st=0;
		}
	}
	if(st==1){
		cout<<"-1"<<endl;
	}
	else{
		sort(h+1,h+m+1);
		long long ans=0;
		long long  l=0,r=INF;
		while(l<=r){
			 long long mid=(l+r)>>1;
			 
			if(check(mid)){
			
			l=mid+1;
			}
			else r=mid-1;
		}
		cout<<l-1<<endl;
		
	}
	
	return 0;
	
	
} 

P1352 没有上司的舞会

1到n个学校职员 每个职员有r[i]的开心值,他们去参加活动 如果上司来了就不开心,问怎么使得所有人的开心值最大,首先找到校长也就是根节点,对根节点进行dfs深搜 每次搜索时类似dp做动态规划就是树形dp 就如这题 每次来到新的一层时 可以选择来和不来 如果他不来 下一层就可以来 他来的话下一层就不来,举例说明 r[u]+dp表示当前点的r[i]不要 也就是他不来 我们取下一个点的最大值

dp[u]表示当前点的最大值并且不拿 他由上一层的拿和不拿决定;

#include<bits/stdc++.h>
using namespace std;
const int N = 6*10e3+10;
vector<int> G[N];
bool xz[N];
long long r[N];
long long dp[N]; 
void dfs(int u){
	for(int i = 0;i<G[u].size();i++){
	dfs(G[u][i]);
	 r[u]+=dp[G[u][i]];
	 dp[u]+=max(r[G[u][i]],dp[G[u][i]]);
	} 
}
int main(){
	int n;
	cin>>n;

	for(int i = 1;i<=n;i++){
		cin>>r[i];
	}
	for(int i = 1;i<=n-1;i++){
		int u,v;
		cin>>u>>v;
		G[v].push_back(u);//后者是前者的上司 所以由后者指向前者 
		xz[u]=true;//他有上司所以不会是校长
	} 
	int root;
	for(int i= 1;i<=n;i++){
		if(!xz[i]){
			root=i;
		}
	}
	dfs(root);
	cout<<max(dp[root],r[root]);
	return 0;
	
}

P1040 [NOIP2003 提高组] 加分二叉树

最后补一场Codeforces Round 966 (Div. 3)

A. Primary Task

枚举就行了 他说型为10^x x>=2 所以1,2为固定为1 0第三位如果是只有三位数的话 必须是>=2,多位数的话必须>=1;

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
int main(){
	int t;
	cin>>t;
for(int i =1;i<=t;i++){
	string a;
	cin>>a;
	if(a[0]!='1'){

	cout<<"No"<<endl;
	continue;}
	if(a[1]!='0'){
		
	cout<<"No"<<endl;
	continue;}
	if(a[2]<'1'){
	cout<<"NO"<<endl;
	continue;
	}
	if(a[2]=='1'&&a.size()==3){
		cout<<"NO"<<endl;
		continue;
	}
	cout<<"Yes"<<endl;
	}

return 0;
}

B. Seating in a Bus

双指针模拟题 用l表示左边 r表示右边 开始状态st为1如果新输入的数是左边-1或者右边+1就可以 不是就把状态变为0 最后判断一下状态是否为0 输出no

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
int main(){
	int t;
	cin>>t;
while(t--){
int n;
cin>>n;
int a[n];
cin>>a[1];
int l=a[1];
int r=a[1];
int st=1;
for(int i = 2;i<=n;i++){
	cin>>a[i];
	if(a[i]==l-1){
		l--;
	}
	else if(a[i]==r+1){
	r++;
	}
	else{
		 st=0;
	} 
}
if(st==0){
	cout<<"NO"<<endl;
}
else cout<<"yes"<<endl;
}

return 0;
}

 C. Numeric String Template

模拟题,首先想到的是哈希数字存字母例如hx[1]可以是a数字hx[2]存b这样 每个数字有对应的字母,基于这个思想我们可以用map,同理 用map存入当前数字ai的位置 然后用字符数组存当前字符所在的位置 最后遍历26个字母 看字符所在的位置对应的数字 是否位置是一一对应

比如 样例 3 5 2 1 3和 a b f d a

我们知道a的位置是1和5 代入第一个位置a[zf[i][0]];得到3

mp【3】存的位置是1 和5 和数字一一对应 

所以字母a为YES,然后看是否所有字母都为yes;

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long
main(){
    int t;
    cin >> t;
    while(t--){
    int n; 
	cin >> n;
    int a[n+1];
    map<int,vector<int> > mp;
    for(int i=0;i<n;i++) {
    	cin >> a[i];
    	mp[a[i]].push_back(i);
	}
    int m;
	cin>>m;
    while(m--){
        string s; 
		cin >> s;
		vector<int> zf[26];
		for(int i=0;i<s.size();i++){
			zf[s[i]-'a'].push_back(i) ; 
		}
		bool st = true;
		for(int i=0;i<26;i++){
			if(!zf[i].empty()){
				int cnt=a[zf[i][0]];
				if(mp[cnt]!=zf[i]){
					st=0;
					break;
				}
			}
		}
	if(st==1&&s.size()==n){
		cout<<"YES"<<endl;
	}
	else cout<<"NO"<<endl ;
    }
	}
    return 0;
}

 D. Right Left Wrong

用双指针贪心模拟,他说找一对l r然后取他们之前的和 很容易想到用前缀和来代替数组 然后找完以后l,r范围内的lr全部变为*,即不可以再用,我们从外到内双指针一直走会得到答案,为什么?

因为 比如 llllrr 你不要在意题目的变*直接从内部开始看 是不是先变l****r再变******他们得到的答案和从外面枚举是一样的你假设只把操作的位置变为* ,第一次从外 *lllr*第二次**ll**,所以从外到内双指针能得到答案

#include<bits/stdc++.h>
using namespace std;
int main(){
	int t;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		long long a[n];
		a[0]=0;
		for(int i = 1;i<=n;i++){
			cin>>a[i];
			a[i]=a[i]+a[i-1];
		}
		string s;
		cin>>s;
		int l,r;
		l=0;r=n-1;
		long long ans=0;
		while(l<r){
			if(s[l]!='L')l++;
			if(s[r]!='R')r--;
			if(s[l]=='L'&&s[r]=='R'){
				ans+=a[r+1]-a[l];
				l++;
				r--;
			}
		}
		cout<<ans<<endl;
	}
	return 0;
	
}

[GDCDC2024]

G - Menji 和 gcd

#include<bits/stdc++.h>
using namespace std;
long long L,R,ans;
int t;
inline void check(long long x){
	if(x<ans)return;
	if(R/x-(L-1)/x>1)ans=x;
}
int main(){
	cin>>t;
	while(t--){
		cin>>l>>r,ans=1;//找一个gk>=l g(k+1)<=r 
		for(int i=1;i<=1000000;++i){
		check(i);
		chk(R/i);
		}
		cout<<ans;
	}
}

 P3946 ことりのおやつ(小鸟的点心)

最短路,在跑s到t的最短路时对于每一个入队列的点进行判断到该点时雪是否已经到顶就好

#include<bits/stdc++.h>
using namespace std;
const int maxn=500001;
int n,m,s,t,g,q,h[maxn],l[maxn],cnt,head[maxn],dis[maxn];
bool vis[maxn];
struct node{
	int nxt,to,w;
}edge[maxn<<2];
void add(int x,int y,int w){
	edge[++cnt]=(node){head[x],y,w};
	head[x]=cnt;
}
void SPFA(){
	memset(dis,63,sizeof(dis));
	dis[s]=0; vis[s]=1;
	queue<int>que; que.push(s);
	while(que.size()){
		int d=que.front();que.pop();vis[d]=0;
		for(int i=head[d];i;i=edge[i].nxt){
			int y=edge[i].to;
			if(dis[y]>dis[d]+edge[i].w){
				dis[y]=dis[d]+edge[i].w;
				if(!vis[y]&&l[y]>=h[y]+dis[y]*q) que.push(y),vis[y]=1;
			}
		}
	}
}
int main(){
	cin>>n>>m>>s>>t>>g>>q;
	for(int i=1;i<=n;i++) cin>>h[i]>>l[i];
	int x,y,z;
	for(int i=1;i<=m;i++){
		cin>>x>>y>>z;
		add(x,y,z),add(y,x,z);
	}
	SPFA();
	if(dis[t]<=g) cout<<dis[t]<<endl;
	else cout<<"wtnap wa kotori no oyatsu desu!"<<endl;
	return 0;
}

I - 不等式

 CSG - 1285

拓扑排序 对于题目的两个特判条件处理一下就好,注意不是直接对每一层赋值 要遍历每一个对

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2*10e5+1;
long long r[N];
vector<int >G[N];
long long v[N];
int n,m;
vector<pair<int,int> >c[N];
	queue<int> q;
 main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	cin>>n>>m;
	int st=0;
	for(int i = 1;i<=m;i++){
		int x,y,z;
		cin>>x>>y>>z;
		G[y].push_back(x);
		G[z].push_back(x);
		r[x]+=2;
		c[x].push_back(make_pair(y,z));
		

	}
	for(int i = 1;i<=n;i++){
		if(r[i]==0){
		q.push(i);
			r[i]--;
			v[i]=1;
		}
	}
	while(!q.empty()){
	int i=q.front();
	q.pop();
		for(int j = 0;j<G[i].size();j++){
				r[G[i][j]]--;
				if(r[G[i][j]]==0){
				q.push(G[i][j]);
				v[G[i][j]]=1;
				}
			}
		for(int k=0;k<c[i].size();k++){
				v[i]=max(v[i],v[c[i][k].first]+v[c[i][k].second]);
				if (v[i] > 1e9) {
				cout << "-1" << endl;
				return 0;

			}
			}
		
	
}
	for(int i = 1;i<=n;i++){
		if(r[i]>0){
			st=1;
			break;
		}
	}
	if(st==1){
		cout<<-1<<endl;
	}
	else{
	long long ans=0;
	for(int i = 1;i<=n;i++){
		ans+=v[i];
	}
	cout << (ans > 1e9 ? -1 : ans) << endl;
}
	return 0;
	
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值