Codeforces Round #776 (Div. 3)

Codeforces Round #776 (Div. 3)

A - Deletions of Two Adjacent Letters

题意

\(T\)组数据,给出一个字符串 \(s\) ,且 \(|s|\) 为奇数,每次可以删除字符串中相邻的两个字母。询问是否可以通过若干次操作,让$s $的值等于字符 \(c\),如果可以输出YES,否则输出NO

数据范围:\(1 \leq |s| \leq 49 ,1 \leq T \leq 10^3\)

题解

我们考虑每一个 \(s_i = c\) 的位置 \(i\),如果该位置之前的字符可以通过若干次操作删成空,后面的字符也可以通过若干次操作删成空,那么该位置就是合法的。

否则,若最终保留\(s_i\),那么若干次不删除该字符的操作后,会形成三个字符组成的字符串,显然不可行。

时间复杂度\(O(\sum |s|)\)

C++ 代码实现

# pragma GCC optimize("Ofast", "inline", "-ffast-math")
# pragma GCC target("avx,sse2,sse3,sse4,mmx")
# include <bits/stdc++.h>
# define YON(x); puts((x)?"Yes":"No");
#define error(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }
# define makep make_pair
# define maket make_tuple
# define eb emplace_back
# define pb push_back
# define fir first
# define sec second
// # define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N = 1e5 + 10;
void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {
cerr << *it << " = " << a << endl;
err(++it, args...);
}
inline int read() {
	int X=0,w=0;char c=0;
	while (!(c>='0'&&c<='9')) w|=c=='-',c=getchar();
	while (c>='0'&&c<='9') X=(X<<1)+(X<<3)+(c^48),c=getchar();
	return w?-X:X;
}
void solve() {
	string s; cin>>s;
	char t; cin>>t;
	bool flag = false;
	for (int i=0;i<s.length();i++) if (s[i] == t) {
		if (i%2 == 0 && (s.length()-(i+1))%2 == 0) flag = true;
	}
	YON(flag);
}
int main() {
	std::ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int tmp; cin>>tmp; 
	while (tmp--) {
		solve();
	}
	return 0;
}

B - DIV + MOD

题意

\(t\) 组数据,每组数据给出 \(l,r,a\) :
求函数 \(f_a(x) = \lfloor\frac{x}{a}\rfloor + x \text{ mod } a\),在\(x \in [l,r]\) 的最大值。

数据满足:\(1 \leq l_i\leq r_i \leq 10^9 , 1 \leq t \leq 10^4 , 1 \leq a_i \leq 10^9\)

题解

考虑 \(x \text{ mod } a\) 的可能值为\([0,a)\),由容斥原理可知:

任何区间长度大于等于 \(a\) 的区间,都存在至少一个数 \(x\) ,让 \(x \text{ mod } a = a-1\)

因此,对于这些区间,\(x\) 的取值等于最大的,除以 \(a\)\(a-1\),那个数,可以让函数前半部分最大。

否则,对于区间长度小于 \(a\) ,函数必然在区间端点取到最值。

时间复杂度\(O(t)\)

# pragma GCC optimize("Ofast", "inline", "-ffast-math")
# pragma GCC target("avx,sse2,sse3,sse4,mmx")
# include <bits/stdc++.h>
# define YON(x); puts((x)?"Yes":"No");
#define error(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }
# define makep make_pair
# define maket make_tuple
# define eb emplace_back
# define pb push_back
# define fir first
# define right rrr
# define sec second
// # define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N = 1e5 + 10;
void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {
cerr << *it << " = " << a << endl;
err(++it, args...);
}
inline int read() {
	int X=0,w=0;char c=0;
	while (!(c>='0'&&c<='9')) w|=c=='-',c=getchar();
	while (c>='0'&&c<='9') X=(X<<1)+(X<<3)+(c^48),c=getchar();
	return w?-X:X;
}
int f(int x,int a) {
	return x/a+x%a;
}
void solve() {
	int l,r,a; cin>>l>>r>>a;
	int left = ((l+1)%a==0)?((l+1)/a):((l+1)/a+1);
	int right = (r+1)/a;
	if (left > right) {
		printf("%d\n",max(f(l,a),f(r,a)));
	} else printf("%d\n",f(right*a-1,a));
}
int main() {
	std::ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int tmp; cin>>tmp; 
	while (tmp--) {
		solve();
	}
	return 0;
}

C - Weight of the System of Nested Segments

题意

数轴上有 \(m\) 个坐标互不相同的点,第 \(i(1\leq i \leq m)\) 个点位置为 \(pos_i\),权值为 \(val_i\)。你需要从中选取 \(n\) 对点,两两组成一个区间,并让这些区间互相嵌套。

求出一种选取点的方案,让选取点的权值和尽量小。

数据范围满足:\(1 \leq 2n \leq m \leq 2\times 10^5\)

题解

由于数轴上的点坐标两两不同,那么我们先选择权值最小的 \(2n\) 个点,可以保证选出的点权值和最小。

然后再对这些点配对组成嵌套区间,只需要对这些点对坐标排序即可。

时间复杂度 \(O(m \log_2 m )\)

C++ 代码示例

# pragma GCC optimize("Ofast", "inline", "-ffast-math")
# pragma GCC target("avx,sse2,sse3,sse4,mmx")
# include <bits/stdc++.h>
# define YON(x); puts((x)?"Yes":"No");
#define error(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }
# define makep make_pair
# define maket make_tuple
# define eb emplace_back
# define pb push_back
# define fir first
# define sec second
// # define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N = 2e5 + 10;
void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {
cerr << *it << " = " << a << endl;
err(++it, args...);
}
inline int read() {
	int X=0,w=0;char c=0;
	while (!(c>='0'&&c<='9')) w|=c=='-',c=getchar();
	while (c>='0'&&c<='9') X=(X<<1)+(X<<3)+(c^48),c=getchar();
	return w?-X:X;
}
struct rec{
	int id,pos,val;
}a[N];
bool cmp1(rec a,rec b) {
	return a.val < b.val;
}
bool cmp2(rec a,rec b) {
	return a.pos<b.pos;
}
void solve() {
	int n,m; cin>>n>>m;
	for (int i=1;i<=m;i++) {
		cin>>a[i].pos>>a[i].val;
		a[i].id = i;
	}
	sort(a+1,a+1+m,cmp1);
	int ans = 0;
	for (int i=1;i<=2*n;i++) ans+=a[i].val;
	cout<<ans<<endl;
	sort(a+1,a+1+2*n,cmp2);
	for (int i=1;i<=n;i++) {
		cout<<a[i].id<<" "<<a[2*n-i+1].id<<endl;
	}
}
int main() {
//	std::ios::sync_with_stdio(false);
//	cin.tie(0), cout.tie(0);
	int tmp; cin>>tmp; 
	while (tmp--) {
		solve();
	}
	return 0;
}

D - Twist the Permutation

题意

\(n\) 个数字 \(1-n\) 组成的排列 \(a\),初始满足\(a_i = i\),通过 $ n $ 次操作,第 \(i(1\leq i \leq n)\) 次操作可以做 \(c_i\) 次 关于\(a_1,...,a_i\) 的循环位移。最后生成数组 \(b_i\)。现在给出 \(b_i\) ,要求输出 \(c_i\)

数据满足:\(1 \leq n \leq 2\times 10^3\)

题解

从后到前考虑,每次通过若干次循环位移让 \(i\) 这个数字循环位移到 \(i\)这个位置即可。

直接模拟,复杂度为 \(O(n^2)\)

C++ 代码示例

# pragma GCC optimize("Ofast", "inline", "-ffast-math")
# pragma GCC target("avx,sse2,sse3,sse4,mmx")
# include <bits/stdc++.h>
# define YON(x); puts((x)?"Yes":"No");
#define error(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }
# define makep make_pair
# define maket make_tuple
# define eb emplace_back
# define pb push_back
# define fir first
# define sec second
// # define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N = 1e5 + 10;
void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {
cerr << *it << " = " << a << endl;
err(++it, args...);
}
inline int read() {
	int X=0,w=0;char c=0;
	while (!(c>='0'&&c<='9')) w|=c=='-',c=getchar();
	while (c>='0'&&c<='9') X=(X<<1)+(X<<3)+(c^48),c=getchar();
	return w?-X:X;
}
int a[N],b[N],ans[N];
void solve() {
	int n; cin>>n;
	for (int i=1;i<=n;i++) cin>>a[i];
	for (int i=n;i>=1;i--) {
		int pos;
		for (int j=1;j<=n;j++) if (a[j] == i) {
			pos = j; break;
		}
		if (pos == i) { ans[i] = 0; continue;}
		ans[i] = pos;
		for (int j=pos+1;j<=i;j++) b[j-pos]=a[j];
		for (int j=1;j<=pos;j++) b[j+i-pos]=a[j];
		for (int j=1;j<=i;j++) a[j]=b[j];
	}
	bool flag = true;
	for (int i=1;i<=n;i++) if (a[i]!=i) {
		flag = false; break;
	}
	if (!flag) {
		puts("-1"); return;
	}
	for (int i=1;i<=n;i++) cout<<ans[i]<<" ";
	cout<<endl;
}
int main() {
	std::ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int tmp; cin>>tmp; 
	while (tmp--) {
		solve();
	}
	return 0;
}

E - Rescheduling the Exam

题意

\(n\) 次考试,共有 \(d\) 天,每次考试安排在第 \(a_i (1\leq a_i \leq d)\) 天,可以改动一次考试的时间,让相邻考试间隔最小值最大。

数据范围满足 \(1 \leq n \leq 2\times 10^5 , 1 \leq d \leq 10^9\)

题解

可以考虑二分答案,设当前需要check的答案为 \(S\),考虑判定。

multiset存储相邻两天之间的空窗间隔,枚举删除每一次考试。

删除后,multiset中也需要对应进行修改,使得其中的数据符合将 \(a_i\) 不安排考试的情况。

接下来考虑插入一个新的考试,间隔最小值不超过 \(S\)

  • 插入在学期的最后一天
  • 插入在两次考试之间

这样,可以完成判断。

这样总时间复杂度为\(O(n {\log_2}^2 n)\) 不能接受。

我们发现,这个二分实际上是可以省去的,只需要计算每次删除一个考试,插入一个考试的答案的最大值即可。

这样时间复杂度为\(O(n log_2 n)\),可以通过。

# pragma GCC optimize("Ofast", "inline", "-ffast-math")
# pragma GCC target("avx,sse2,sse3,sse4,mmx")
# include <bits/stdc++.h>
# define YON(x); puts((x)?"Yes":"No");
#define error(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }
# define makep make_pair
# define maket make_tuple
# define eb emplace_back
# define pb push_back
# define fir first
# define sec second
// # define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N = 2e5 + 10;
void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {
cerr << *it << " = " << a << endl;
err(++it, args...);
}
inline int read() {
	int X=0,w=0;char c=0;
	while (!(c>='0'&&c<='9')) w|=c=='-',c=getchar();
	while (c>='0'&&c<='9') X=(X<<1)+(X<<3)+(c^48),c=getchar();
	return w?-X:X;
}
int n,d;
int a[N];
void solve() {
	n=read();d=read();
	for (int i=1;i<=n;i++) a[i]=read();
	int mx = 0;
	sort(a+1,a+1+n);
	multiset<int>st;
	for (int i=1;i<=n;i++) st.insert(a[i]-a[i-1]-1);
	int ans = 0;
	for (int i=1;i<=n;i++) {
		st.erase(st.find(a[i]-a[i-1]-1));
		int bk = d-a[n]-1;
		if (i!=n) {
			st.erase(st.find(a[i+1]-a[i]-1));
			st.insert(a[i+1]-a[i-1]-1);
		} else bk = d-a[n-1]-1;
		int res = *st.begin();
		int mx = *(--st.end());
		res = min(res,max(bk,(mx-1)/2));
		ans = max(ans,res);
		if (i!=n) {
			st.erase(st.find(a[i+1]-a[i-1]-1));	
			st.insert(a[i+1]-a[i]-1);
		}
		st.insert(a[i]-a[i-1]-1);
	}
	printf("%d\n",ans);
}
int main() {
	int tmp = read();
	while (tmp--) {
		solve();
	}
	return 0;
}

F - Vitaly and Advanced Useless Algorithms

题意

\(n\) 项作业,每项作业离ddl还有 \(a_i\) 个小时,有 \(m\) 次操作\(\{e_i,t_i,p_i\}\),每次操作可以花费\(t_i\)个小时,将作业\(e_i\)推进百分之\(t_i\)。输出可以完成作业的一种方法,或者输出不能完成作业。

数据满足\(1 \leq n,m \leq 10^5 , 1 \leq a_i \leq 10^9\)

题解

对每一项作业进行 \(dp\) 计算完成该作业最小需要的时间,并记录方案。

这实际上是背包问题,可以从前往后更新,\(f[i][j]\)表示前\(i\)个操作,完成百分比为\(j\)的最小时间。

然后,贪心地从前往后完成每个作业,如果出现无法完成,则输出\(-1\)

这样做时间复杂度为\(O(100n)\)

# include <bits/stdc++.h>
# define time TIME
using namespace std;
const int N=1e5+10;
const int inf = 1e9+7;
int a[N];
struct qwq{ int t,p,id;};
vector<qwq>v[N];
int f[N][105];
vector<int>ans[N];
int time[N];
struct rec{
	int i,j,op;
}g[N][105];
int main() {
//	freopen("a.in","r",stdin);
	int t; cin>>t;
	while (t--) {
		int n,m; cin>>n>>m;
		for (int i=1;i<=n;i++) {
			cin>>a[i];
			v[i].clear();
			time[i]=-1;
		}
		for (int i=1;i<=m;i++) {
			int c,t,p; cin>>c>>t>>p;
			v[c].push_back({t,p,i});
		}
		bool flag = true;
		for (int c=1;c<=n;c++) {
			if (v[c].size() == 0) {
				puts("-1"); flag = false; break;
			}
			for (int i=0;i<=v[c].size();i++)
				for (int j=0;j<=100;j++)
					f[i][j] = inf, g[i][j].i=g[i][j].j=g[i][j].op=0;
			f[0][0] = 0;
			for (int i=0;i<v[c].size();i++)
				for (int j=0;j<=100;j++) {
					if (f[i+1][j] > f[i][j]) {
						f[i+1][j]=f[i][j];
						g[i+1][j] = (rec){i,j,-1};
					}
					if (f[i+1][min(j+v[c][i].p,100)] > f[i][j]+v[c][i].t) {
						f[i+1][min(j+v[c][i].p,100)] = f[i][j]+v[c][i].t;
						g[i+1][min(j+v[c][i].p,100)] = (rec){i,j,v[c][i].id};
					}
				}
			if (f[v[c].size()][100]>=inf) {
				puts("-1"); 
				flag = false;
				break;
			}
			int t = v[c].size(), p = 100;
			ans[c].clear();
			while (p>0) {
				int id = g[t][p].op;
				if (id != -1) ans[c].push_back(id);
				int tmp1 = g[t][p].i,tmp2 = g[t][p].j;
				t = tmp1; p = tmp2;
			}
			time[c] = f[v[c].size()][100];
		}
		if (!flag) {
			continue;
		}
		int res = 0;
		for (int i=1;i<=n;i++) {
			if (res+time[i]>a[i]) {
				puts("-1"); flag = false; break;
			}
			res+=time[i];
		}
		if (!flag) {
			continue;
		}
		int sum = 0;
		for (int i=1;i<=n;i++) sum+=ans[i].size();
		printf("%d\n",sum);
		for (int i=1;i<=n;i++)
			for (int x:ans[i]) printf("%d ",x);
		puts("");		
	}
	return 0;
}

G - Counting Shortcuts

题意

\(n\) 个点 \(m\) 条边,边权都是 \(1\) 的有向图,求出最短路和次短路条数的和。

数据满足\(1 \leq n,m \leq 2\times 10^5\)

题解

dijkstra 记录最短路次短路值及其次数,即可。

是个模板题,时间复杂度\(O((n+m)\log_2 n)\)

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
using namespace std;
const int maxd=4e5+10,maxb=4e5+10;
const int mo = 1e9+7;
int head[maxd],tot=1;
struct asd{
    int from,to,next,val;
}b[maxb<<1];
int n,m;
void ad(int aa,int bb,int cc){
    b[tot].from=aa;
    b[tot].to=bb;
    b[tot].val=cc;
    b[tot].next=head[aa];
    head[aa]=tot++;
}
struct jie{
    int num,dis,jud;
    jie(int aa=0,int bb=0,int cc=0){
        num=aa,dis=bb,jud=cc;
    }
    bool operator < (const jie& A) const{
        return dis>A.dis;
    }
};
priority_queue<jie> q;
int dis[maxd][3],cnt[maxd][3];
bool vis[maxd][3];
void dij(int xx){
	for (int i=1;i<=n;i++) {
		memset(dis[i],0x3f,sizeof(dis[i]));
		memset(cnt[i],0,sizeof(cnt[i]));
		memset(vis[i],0,sizeof(vis[i]));
	}
    dis[xx][0]=0,cnt[xx][0]=1;
    q.push(jie(xx,0,0));
    while(!q.empty()){
        int now=q.top().num;
        int judd=q.top().jud;
        q.pop();
        if(vis[now][judd]) continue;
        vis[now][judd]=1;
        for(int i=head[now];i!=-1;i=b[i].next){
            int u=b[i].to;
            int ndis=dis[now][judd]+b[i].val;
            if(ndis<dis[u][0]){
                if(dis[u][0]!=0x3f3f3f3f){
                    dis[u][1]=dis[u][0];
                    cnt[u][1]=cnt[u][0];
                    q.push(jie(u,dis[u][0],1));
                }
                dis[u][0]=ndis;
                cnt[u][0]=cnt[now][judd];
                q.push(jie(u,ndis,0));
            }
            else if(ndis==dis[u][0]){
                (cnt[u][0]+=cnt[now][judd])%=mo;
            }
            else if(ndis==dis[u][1]){
                (cnt[u][1]+=cnt[now][judd])%=mo;
            }
            else if(ndis<dis[u][1]){
                dis[u][1]=ndis;
                cnt[u][1]=cnt[now][judd];
                q.push(jie(u,ndis,1));
            }
        }
    }
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        tot=1;
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) head[i]=-1;
        int qd,zd;
        scanf("%d%d",&qd,&zd);
        for(int i=1;i<=m;i++){
            int aa,bb,cc=1;
            scanf("%d%d",&aa,&bb);
            ad(aa,bb,cc);
            ad(bb,aa,cc);
        }
        dij(qd);
        int ans=cnt[zd][0];
        if(dis[zd][0]==dis[zd][1]-1) (ans+=cnt[zd][1])%=mo;
        printf("%d\n",ans);
    }
    return 0;
}
posted @ 2022-03-09 15:49  Maystern  阅读(311)  评论(0编辑  收藏  举报