Codeforces Round #591 (Div. 2, based on Technocup 2020 Elimination Round 1) 题解

借了某神仙的号来打Div2,结果手速过C之后莽了个错误结论。好不容易把结论改对了结果喜闻乐见被DDos攻击了?(上次DDos好像也是Technocup吧)

之后就果断颓废了

A

特判2,之后奇数答案为1,偶数答案为0

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=10000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define fir first
#define sec second
#define mp(a,b) make_pair(a,b)
#define pb(a) push_back(a)
#define maxd 998244353
#define eps 1e-8
int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

int main()
{
	int q=read();
	while (q--)
	{
		int n=read();
		if (n==2) puts("2");
		else if (n&1) printf("%d
",1);
		else puts("0");
	}
	return 0;
}

B

不难发现你可以把一个字符串统一成只由一个原串中出现的字母,然后就变成了判断两个字符串是否有相同字符了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=10000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define fir first
#define sec second
#define mp(a,b) make_pair(a,b)
#define pb(a) push_back(a)
#define maxd 998244353
#define eps 1e-8
int n,tax[40];
char s[1010],t[1010];

int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

int main()
{
	int q=read();
	while (q--)
	{
		scanf("%s",s+1);
		scanf("%s",t+1);
		n=strlen(s+1);
		rep(i,1,n) tax[s[i]-'a']=1;
		int ok=0;
		rep(i,1,n)
			if (tax[t[i]-'a']) {ok=1;break;}
		if (ok) puts("YES");else puts("NO");
		rep(i,0,26) tax[i]=0;
	}
	return 0;
} 

C

答案具有二分性于是考虑二分答案。预处理每一个位置对捐赠值的贡献,二分所需天数,暴力贪心填就可以了,时间复杂度貌似被写成了(O(qnlog^2n)),似乎可以1个(log)(但是能过还管他干嘛)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=10000;
const db pi=acos(-1.0);
#define int long long
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define fir first
#define sec second
#define mp(a,b) make_pair(a,b)
#define pb(a) push_back(a)
#define maxd 998244353
#define eps 1e-8
int n,a[200200],pri[200200],p[200200],lim,tmp[200200];

int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

bool chk(int len)
{
	rep(i,1,len) tmp[i]=a[i];
	sort(tmp+1,tmp+1+len);
	reverse(tmp+1,tmp+1+len);
	ll ans=0;
	rep(i,1,len)
	{
		ans+=pri[i]*tmp[i];
		if (ans>=lim) return 1;
	}
	return 0;
}


signed main()
{
	int q=read();
	while (q--)
	{
		n=read();
		rep(i,1,n) pri[i]=read()/100;
		sort(pri+1,pri+1+n);
		reverse(pri+1,pri+1+n);
		rep(i,1,n) a[i]=0;
		int pro1=read(),gap=read();
		for (int i=gap;i<=n;i+=gap) a[i]+=pro1;
		pro1=read();gap=read();
		for (int i=gap;i<=n;i+=gap) a[i]+=pro1;
		lim=read();int l=1,r=n,ans=-1;
		while (l<=r)
		{
			int mid=(l+r)>>1;
			if (chk(mid)) {ans=mid;r=mid-1;}
			else l=mid+1;
		}
		printf("%lld
",ans);
	}
	return 0;
}

D

直接考虑哪些数字进行了操作比较麻烦,我们考虑那些没有进行的操作的数字,最后用总数字种类数减一下

不难发现未被操作的数字从小到大排序后一定是一段区间,这个用反证法就比较显然。之后就可以直接dp以(i)结尾的最长不操作的区间长度,判一下前一个数字的区间是否合法就可以了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=10000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define fir first
#define sec second
#define mp(a,b) make_pair(a,b)
#define pb(a) push_back(a)
#define maxd 998244353
#define eps 1e-8
int n,a[300100],x[300300],m,f[300300],l[300300],r[300300];

int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

int main()
{
	int q=read();
	while (q--)
	{
		n=read();
		rep(i,1,n) x[i]=a[i]=read();
		rep(i,0,n) {l[i]=maxd;r[i]=0;}
		rep(i,1,n)
		{
			l[a[i]]=min(l[a[i]],i);
			r[a[i]]=max(r[a[i]],i);
		}
		sort(x+1,x+1+n);
		m=unique(x+1,x+1+n)-x-1;
		rep(i,1,m)
			if (l[x[i]]>r[x[i-1]]) f[i]=f[i-1]+1;
			else f[i]=1;
		int ans=0;
		rep(i,1,m) ans=max(ans,f[i]);
		printf("%d
",m-ans);
	}
	return 0;
}

E

感觉这个题就十分的套路

(f_{i.0/1})表示(i)不能/能向上时,其子树的最大价值和。转移的话考虑所有的儿子是否往上连。记(f_{v,1}+w>f_{v,0})的点为好点。好点个数(<k)时直接暴力转移(max(f_{v,0}+w,f_{v,1}))

否则我们需要选择最优的(k-1)(f_{v,1}+w)进行转移,随便移个项得到可以将(f_{v,1}+w-f_{v,0})的值从大到小,前(k-1)大的儿子考虑向上走,对第(k)大的分类讨论,最后处理剩下的儿子。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=10000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define fir first
#define sec second
#define mp(a,b) make_pair(a,b)
#define pb(a) push_back(a)
#define maxd 998244353
#define eps 1e-8
struct node{int to,nxt,cost;}sq[1001000];
int all=0,head[500500];
int n,k,tot=0;
ll f[500500][2];
pii son[500500];
bool cmp(pii p,pii q)
{
	int v1=p.fir,v2=q.fir;
	return f[v1][1]+p.sec-f[v1][0]>f[v2][1]+q.sec-f[v2][0];
}

int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

void add(int u,int v,int w)
{
	all++;sq[all].to=v;sq[all].nxt=head[u];sq[all].cost=w;head[u]=all;
}

void dfs(int u,int fu)
{
	int cnt=0;
	for (int i=head[u];i;i=sq[i].nxt)
	{
		int v=sq[i].to;
		if (v==fu) continue;
		dfs(v,u);
		if (f[v][1]+sq[i].cost>f[v][0]) cnt++;
	}
	if (cnt<k)
	{
		for (int i=head[u];i;i=sq[i].nxt)
		{
			int v=sq[i].to;
			if (v==fu) continue;
			ll now=max(f[v][0],f[v][1]+sq[i].cost);
			f[u][0]+=now;f[u][1]+=now;
		}
	}
	else
	{
		tot=0;
		for (int i=head[u];i;i=sq[i].nxt)
		{
			int v=sq[i].to;
			if (v==fu) continue;
			son[++tot]=mp(v,sq[i].cost);
		}
		sort(son+1,son+1+tot,cmp);
		rep(i,1,k-1)
		{
			int v=son[i].fir,w=son[i].sec;
			f[u][0]+=(f[v][1]+w);
		}
		f[u][1]=f[u][0];
		int v=son[k].fir,w=son[k].sec;
		f[u][0]+=f[v][1]+w;
		f[u][1]+=max(f[v][0],f[v][1]);
		rep(i,k+1,tot)
		{
			int v=son[i].fir;
			f[u][0]+=max(f[v][0],f[v][1]);
			f[u][1]+=max(f[v][0],f[v][1]);
		}
	}
}

int main()
{
	int T=read();
	while (T--)
	{
		n=read();k=read();
		rep(i,1,n-1)
		{
			int u=read(),v=read(),w=read();
			add(u,v,w);add(v,u,w);
		}
		dfs(1,0);
		printf("%lld
",max(f[1][0],f[1][1]));
		all=0;
		rep(i,1,n) f[i][0]=f[i][1]=head[i]=0;
	}
	return 0;
}

F

感觉我做过这个题的原题

暴力的话就是枚举区间([l,r])然后暴力做一个栈

注意到([l,r])合法等价于([1,l-1])([1,r])这两个区间的栈中元素完全一致

那么就只需要从头开始做一遍栈,沿途记录栈中元素的(hash)值,开个(map)记一下就可以了

似乎并没有卡自然溢出?

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
typedef unsigned long long ull;
const int N=10000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define fir first
#define sec second
#define mp(a,b) make_pair(a,b)
#define pb(a) push_back(a)
#define maxd 998244353
#define eps 1e-8
#define bas 300007
int n,a[300300],tp,sta[300300];
map<ull,int> mp;
ull hsh[300300];

int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

int main()
{
	int T=read();
	while (T--)
	{
		n=read();
		rep(i,1,n) a[i]=read();
		tp=0;ll ans=0;mp.clear();mp[0]=1;
		rep(i,1,n)
		{
			if ((tp) && (sta[tp]==a[i])) tp--;
			else {sta[++tp]=a[i];hsh[tp]=hsh[tp-1]*bas+a[i];}
			ans+=mp[hsh[tp]];mp[hsh[tp]]++;
		}
		printf("%lld
",ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/encodetalker/p/11632920.html