2019 ICPC Asia-East Continent Final

A-City

传统签到题!
不妨枚举横竖两个维度的长度,只要都是偶数就满足条件,简单计数统计满足这种长度的线段的数量即可。
斜着的线段因为不确定往哪边斜,数量要乘 \(2\)!!!

查看代码
#include<bits/stdc++.h>
using namespace std;
long long ans;
int n,m;
int main(){
	cin>>n>>m;
	for(int i=0;i<=n;++i){
		for(int j=0;j<=m;++j){
			if(i%2||j%2||(i==0&&j==0))continue;
			ans+=((i!=0&&j!=0)?2:1)*1ll*(n-i+1)*(m-j+1);
		}
	}
	cout<<ans;
	return 0;
}

E-Flow

首先可以发现最大的流量一定是总流量除以最短路取下整!
对于每条简单路径先把内部的边排序。
然后对于每一层,先看看目前能不能达到这个流量,不行就加大到下一层(因为排了序),再加就超过了的话只要补上缺的一部分即可!

查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,tot,s[100005],a[100005];
pair<int,int>nxt[100005];
int sum[100005];
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m;
	int res=0;
	memset(s,-1,sizeof(s));
	for(int i=1;i<=m;++i){
		int x,y,z;
		cin>>x>>y>>z;
		if(x==1){
			++tot;
			s[y]=z;
		}
		else nxt[x]=make_pair(y,z);
		res+=z;
	}
	res/=(m/tot);
	for(int i=2;i<=n;++i){
		if(s[i]!=-1){
			int cnt=0;
			a[++cnt]=s[i];
			int u=i;
			while(u!=n){
				a[++cnt]=nxt[u].second;
				u=nxt[u].first;
			}
			sort(a+1,a+cnt+1);
			for(int j=1;j<=cnt;++j)sum[j-1]+=a[j]-a[j-1];
		}
	}
	int ans=0,tot=sum[0];
	int x=0;
	while(tot+sum[x+1]<res){
		tot+=sum[++x];
		ans+=x*sum[x];
	}
	++x;
	ans+=x*(res-tot);
	cout<<ans;
	return 0;
}

H-King

随机化算法好!
因为长度要超过 \(\frac{n}{2}\),所以一定会有挨着或者中间隔了一个的情况!
所以我只要 shuffle() 一个顺序数组,取前 \(100\)check() 一下就可以了!
可以发现,取前 \(100\) 个几乎不可能挂!
然后写个逆元啥的,问题就解决了!

查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int t,n,p,r[200005],a[200005];
int qpow(int a,int b){
	int ans=1,base=a;
	while(b){
		if(b&1)ans=ans*base%p;
		base=base*base%p;
		b>>=1;
	}
	return ans;
}
int inv(int x){
	return qpow(x,p-2);
}
mt19937 rnd(time(0));
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>t;
	while(t--){
		cin>>n>>p;
		for(int i=1;i<=n;++i)cin>>a[i];
		for(int i=1;i<n;++i)r[i]=i+1;
		shuffle(r+1,r+n,rnd);
		int maxn=0;
		for(int i=1;i<=100;++i){
			int x=r[i];
			int q=a[x]*inv(a[x-1])%p;
			int invq=inv(q),s=a[x-1],sum=0;
			for(int j=x-1;j>=1;j--){
				if(s==a[j])++sum,s=s*invq%p;
			}
			s=a[x];
			for(int j=x;j<=n;++j)if(s==a[j])++sum,s=s*q%p;
			maxn=max(maxn,sum);
		}
		for(int i=1;i<n-1;++i)r[i]=i+2;
		shuffle(r+1,r+n-1,rnd);
		for(int i=1;i<=100;++i){
			int x=r[i];
			int q=a[x]*inv(a[x-2])%p;
			int invq=inv(q),s=a[x-2],sum=0;
			for(int j=x-2;j>=1;j--){
				if(s==a[j])++sum,s=s*invq%p;
			}
			s=a[x];
			for(int j=x;j<=n;++j)if(s==a[j])++sum,s=s*q%p;
			maxn=max(maxn,sum);
		}
		if(maxn<n/2.0)cout<<-1<<'\n';
		else cout<<maxn<<'\n';
	}
}

M-Value

非常抽象啊!以至于我一开始打算网络流
就是,你发现,对于一个数 \(k\),如果它对谁开根都不是整数,那么选不选这个数的影响范围只有 \(k^2,k^3...\),元素数量是 \(\log_kn\) 级别的。
然后你发现,满足条件的 \(k\) 只能是 \(1\)\(\sqrt{n}\)
那么我只有 \(2^{\log_kn}\) 搜索!
复杂度 \(\Theta(\sqrt{n}\times 2^{\log_kn}) \le \Theta(n\sqrt{n})\)
稳过!!!

查看代码
#include<bits/stdc++.h>
using namespace std;
int n,a[100005],tot,b[100005];
vector<int>v[355];
bool vis[100005],flg[25];
long long ans;
void check(int x){
	long long res=0;
	for(int i=0;i<v[x].size();++i)if(flg[i+1])res+=a[v[x][i]];
	for(int i=0;i<v[x].size();++i){
		for(int j=0;j<i;++j){
			if((i+1)%(j+1))continue;
			if(flg[i+1]&&flg[j+1])res-=b[v[x][i]];
		}
	}
	ans=max(ans,res);
	return;
}
void dfs(int x,int cur){
	if(cur==v[x].size()+1){
		check(x);
		return;
	}
	flg[cur]=0;
	dfs(x,cur+1);
	flg[cur]=1;
	dfs(x,cur+1);
	flg[cur]=0;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;++i)cin>>a[i];
	for(int i=1;i<=n;++i)cin>>b[i];
	for(int i=2;i<=sqrt(n);++i){
		if(vis[i])continue;
		vis[i]=1;
		tot++;
		for(int j=i;j<=n;j*=i)vis[j]=1,v[tot].push_back(j);
	}
	long long sum=0;
	for(int i=1;i<=tot;++i){
		ans=-1e9;
		memset(flg,0,sizeof(flg));
		dfs(i,1);
		sum+=ans;
	}
	for(int i=1;i<=n;++i)if(!vis[i])sum+=a[i];
	cout<<sum;
	return 0;
}
posted @ 2023-01-14 14:38  Forever1507  阅读(57)  评论(0编辑  收藏  举报