2019 HCW 19 Team Round (ICPC format) A、C、D、G(换根dp)、H、I、J、L

A. Amsopoly Simple Version 签到题

#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e5+10;
int vis[N];
int cnt[4];
int num[4];
int c1,c2,c3,n;
int va,vb,vc;
bool flag=0;
int ans=0;
void cal(int &c,int s,int ty)
{
	c=(c+s)%(n+1);
	if(c==0) return ;
	if(vis[c]==0)
	{
		cnt[ty]=0;
		num[ty]++;
		vis[c]=ty;
	}
	else if(vis[c]==ty) cnt[ty]++;
	else 
	{
		flag=1;
	}
}
bool valid()
{
	if(flag) return 1;
	bool f=0;
	for(int i=1;i<=3;++i)
	{
		if(cnt[i]<=num[i]) return 0;
	}
	return 1;
}
int main()
{
	cin>>n>>va>>vb>>vc;
	while(1)
	{
		cal(c1,va,1);
		if(valid()) break;
		ans++;
		cal(c2,vb,2);
		if(valid()) break;
		ans++;
		cal(c3,vc,3);
		if(valid()) break;
		ans++;
	}
	if(flag)
	printf("%d\n",ans+1);
	else printf("3000000000\n");
}

C. Countering Terrorists

二分w加dp去check。

怎么dp呢?设dp[i][j]为前i个物品,使用了j个第一种,dp[i][j]个第二种的最小方案数。那么枚举j,可以得到转移方程:

 dp[i][j+1]=min(dp[i][j+1],dp[k][j]);

dp[i][j]=min(dp[i][j],dp[k0][j]+1);

k是a[i]-w时的上一个位置,

k0是a[i]-2*w的上一个位置。

#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=2e3+10;
const ll inf=0x3f3f3f3f3f3f3f;
int n;
int p,q;
ll a[N],b[N];
int lb;
ll dp[N][N];
int getid(ll x)
{
    return upper_bound(b+1,b+1+lb,x)-b;
}
bool check(int w)
{
    if (1ll*w*p+2ll*w*q>=a[n]-a[1]+1)
		return 1;
    
    memset(dp,inf,sizeof(dp));
    dp[0][0]=0;
    dp[1][0]=1;
    dp[1][1]=0;
    ll flag;
    for(int i=2;i<=n;++i)
    {
        flag=inf;
        int k=getid(a[i]-w)-1;
        for(int j=0;j>n>>p>>q;
	for(int i=1;i<=n;++i)
    {
        scanf("%lld",&a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+1+n);
    sort(a+1,a+1+n);
    lb=unique(b+1,b+1+n)-b-1;
    int l=1,r=1e9;
    int ans=0;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(check(mid))
        {
            r=mid-1;
            ans=mid;
        }
        else l=mid+1;
    }
    printf("%d",ans);
}

D. Dahlia The Champion  

记录下斜率去下重就可以了

#include
using namespace std;
const int N = 5e5+100;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
 
pairhs[N];
int main()
{
	ll x0,y0,r,x,y;
	int n,ans=0;
	scanf("%lld%lld%lld%d",&x0,&y0,&r,&n);
	int m=0;
	for(int i=1;i<=n;i++){
		scanf("%lld%lld",&x,&y);
		ll t1=y0-y,t2=x0-x;
		if(t1*t1+t2*t2>r*r) continue;
		ll t3 = gcd(t1,t2);
		if(t3<0) t3=-t3;
		t1/=t3;t2/=t3;
	//	printf("t1:%lld t2:%lld t3:%lld\n",t1,t2,t3);
		hs[++m]=make_pair(t1,t2);
	}
	if(m==0)
	{
		printf("0\n");
		return 0;
	}
	sort(hs+1,hs+1+m);
	ll l=hs[1].first;r=hs[1].second;
	ans=1;
	for(int i=2;i<=m;++i)
	{
		if(l==hs[i].first&&r==hs[i].second) continue;
		else
		{
			ans++;
			l=hs[i].first;
			r=hs[i].second;
		}
	}
	printf("%d\n",ans);
}

G. Get Higher and Higher

换根dp搞一搞就可以了,不过有人的做法是直接求直径比较大小?很妙

#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e5+10,inf=0x3f3f3f3f;
int n,m;
vectorG[N],g[N],mx[N],mx1[N];
int dp[N],d[N];
int ans1,ans2;
void dfs1(int u,int fa)
{
	//dp[u]=inf;
	for(int v:G[u])
	{
		if(v==fa) continue;
		dfs1(v,u);
		dp[u]=max(dp[u],dp[v]);
	}
	dp[u]++;
}
void dfs2(int u,int fa)
{
	dp[u]=0;
	for(int v:G[u])
	{
		dp[u]=max(dp[u],dp[v]);
		mx[u].push_back(dp[u]);
	}
	dp[u]++;
	ans1=max(ans1,dp[u]);
	int t1=-inf;	
	for(int i=G[u].size()-1;i>=0;--i)
	{
		dp[u]=t1;
		int v=G[u][i];
		if(i) dp[u]=max(dp[u],mx[u][i-1]);
		dp[u]++;
		t1=max(t1,dp[v]);
		if(v!=fa) dfs2(v,u);
	}
}
void dfs3(int u,int fa)
{
	//d[u]=inf;
	for(int v:g[u])
	{
		if(v==fa) continue;
		dfs3(v,u);
		d[u]=max(d[u],d[v]);
	}
	d[u]++;
}
dfs4(int u,int fa)
{
	d[u]=0;
	for(int v:g[u])
	{
		d[u]=max(d[u],d[v]);
		mx1[u].push_back(d[u]);
	}
	d[u]++;
	ans2=min(ans2,d[u]);
	int t1=-inf;	
	for(int i=g[u].size()-1;i>=0;--i)
	{
		d[u]=t1;
		int v=g[u][i];
		if(i) d[u]=max(d[u],mx1[u][i-1]);
		d[u]++;
		t1=max(t1,d[v]);
		if(v!=fa) dfs4(v,u);
	}
}
int main()
{
	cin>>n;
	for(int i=1;i>m;
	for(int i=1;i

H. Houston, Are You There? 

由于这场是省赛模拟赛,所以这个题是队友写的,贴代码了。

#include
using namespace std;
int vis[10],n,f;
struct node{
	int u,v;
}a[10],ans[10];
void dfs(int cur,int flag,int cnt){
	if(f) return;
	if(cnt==n+1&&!f){
		for(int i=1;i<=n;i++){
			cout<>n;
	for(int i=1;i<=n;i++) cin>>a[i].u>>a[i].v;
	for(int i=1;i<=n;i++){
		memset(vis,0,sizeof vis);
		vis[i]=1;
		ans[1].u=i;
		ans[1].v=0;
		dfs(i,0,2);
		memset(vis,0,sizeof vis);
		vis[i]=1;
		ans[1].u=i;
		ans[1].v=1;
		dfs(i,1,2);
	}
}

I. Imitater The Potato 博弈论

题意:n堆物品,每堆,a[i]个石子,两个人,lowie先手,imitater后手,每次一个可以选择两个操作的其中一个。

1、从其中一堆拿走一个

2、所有堆各拿走一个,当一个堆中为空,不能执行该操作

拿掉最后一个的获胜。

做法:通过简单的观察,当前总数为奇数的时候是对自己是优势局面。由于自己是先手,那我可以通过微调使得自己永远是优势局面。

那么考虑总数为偶数的时候怎么利用自己是先手的优势来逆转局面?

 

当n为奇数的时候会发现自己无论都赢不了。

因为当你执行第二个操作,总数变成奇数,那么对面是优势局面,对面变成了先手且是优势局面,他可以通过自己最聪明的做法使得自己赢

当n为偶的时候才是有可能逆转局面的。

总数为偶数,执行第二种操作,总数还是偶数,成功的把偶数(劣势局面)转给对手,对手也可以通过相同的方法转给我,那么就变成拼谁最后使得不能执行第二个操作时的局势。当最小值为偶数,那么我不能把劣势转给对方,是我输;

最小值为奇数,我必赢。

代码:

#include
using namespace std;
typedef long long ll;
const int N=1e3+10;
ll a[N];
int main(){
	ll mi=1e14;
	ll sum=0;
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
    {
		cin>>a[i];
		sum+=a[i];
		mi=min(mi,a[i]);
	}

	if(sum&1)printf("lowie");
	else{
		if(n&1)printf("imitater");
		else {
			if(mi%2==0)printf("imitater");
			else printf("lowie");
		}
	}
}

J. Jumpity Digits 签到题,暴力搞一搞就可以了

include
using namespace std;
int main()
{
	string s,ans="0";
	int flag=0;
	cin>>s;
	for(int i=0;ians) ans=t;
			}
		}
	}
	if(flag) cout<

L. Left or Right? How about neither?

相邻的建图,数字一样建立一个虚点,虚点与这些点的权值是0,跑最短路就可以了,简单题

#include 
 
using namespace std;
 
#define ll long long
ll input(){
	ll x=0,f=0;char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return f? -x:x;	
}
 
const int N=2e5+7;
#define clr(a,b) memset(a,b,sizeof a)
 
struct edge{ll v,w,next;}e[5*N];
int head[N],Cnt=0;
 
ll n,L,R,C,s,t;
ll a[N],b[N];
ll dis[N];
struct node{
	ll u,d;
	bool operator <(const node& rhs) const {return d>rhs.d;}
};
 
void Ins(ll u,ll v,ll w){
	e[++Cnt]=(edge){v,w,head[u]},head[u]=Cnt;
}
 
priority_queue  Q;
 
void Dijkstra(){
	clr(dis,0x3f);
	dis[s]=0;
	Q.push((node){s,0});
	while(!Q.empty()){
		node fr=Q.top(); Q.pop();
		ll u=fr.u,d=fr.d,v,w;
		if(d!=dis[u]) continue;
		for(int i=head[u];i;i=e[i].next){
			if(dis[u]+(w=e[i].w)

 

你可能感兴趣的:(codeforce题解)