2020-2021 ACM-ICPC, Asia Seoul Regional Contest

Solved:

  • B、Commemorative Dice
  • C、Dessert Café
  • E、Imprecise Computer
  • G、Mobile Robot
  • H、Needle

B、Commemorative Dice

签到

int gcd(int a,int b)
{
    if(b == 0)return a;
    return gcd(b,a%b);
}
int main()
{
    int a[10],b[10];
    for(int i=1;i<=6;i++)scanf("%d",&a[i]);
    for(int i=1;i<=6;i++)scanf("%d",&b[i]);
    int sum=0;
    for(int i=1;i<=6;i++){
        for(int j=1;j<=6;j++){
            if(a[i]>b[j])sum++;
        }
    }
    int num=gcd(sum,36);
    printf("%d/%d",sum/num,36/num);
}

C、Dessert Café

题意:
题目给出一棵树,树上有一些结点是特殊点,问在这些特殊点之间的路径上(包括特殊点在内)一共有多少个结点。

想法:
考虑对整棵树进行 \(DFS\) ,从一个点开始,去求这个结点的子树中拥有特殊点的个数,如果某个点的子树中特殊点的个数在 \(2\sim (k-1)\) 之间,那么这个点就在特殊点的之间的路径上。

代码:

int n,k;
vector<int>mp[maxn];
int num[maxn]; 
bool isA[maxn];
int ans=0;
void dfs(int u,int f)
{
	int cnt=0;
	for(int i=0;i<mp[u].size();i++)
	{
		int v=mp[u][i];
		if(v!=f)
		{
			dfs(v,u);
			num[u]+=num[v];
			if(num[v]) cnt++;
		}
	}
	if(num[u]!=k) cnt++;
	//dbg(u);
	if(cnt>=2&&!isA[u])  ans++;
	//dbg(ans);
}
void run()
{
	n=rd();
	k=rd();
	for(int i =1;i<n;i++)
	{
		int u=rd(),v=rd(),w=rd();
		mp[u].push_back(v);
		mp[v].push_back(u);
	}
	for(int i=0;i<k;i++)
	{
		int x=rd();
		num[x]=1;
		isA[x]=true;
		ans++;
		//cout<<ans<<" sss"<<endl;
	}
	dfs(1,-1);
	cout<<ans<<endl;
}
signed main()
{	
	run();
	return 0;
}

E、Imprecise Computer

队友tql

int n,k;
int dp[maxn];
void run()
{
	n=rd();
	for(int i=1;i<=n;i++) dp[i]=rd();
	bool flag=1;
	for(int i=1;i<=n;i++)
	{
		if(dp[i]>=2) {
			flag=0;
			break ; 
		}
		else{
			if(dp[i]) {
				if(dp[i+1]) dp[i+1]--;
				else dp[i+1]++;
 			}
		}
	}
	puts((flag&&dp[n]==0)?"YES":"NO");
}
signed main()
{	
	run();
	return 0;
}

G、Mobile Robot

题意:
\(n\) 个机器人,编号从 \(1 \sim n\),告诉你每个机器人在坐标轴上的位置,问通过对每个机器人的移动,让编号 \(i \ 和\ i-1\)号机器人($i\in \left[ 2,n\right] $)的距离保持在 \(d\),问所有机器人中移动距离的最大值的最小值是多少。

想法:
首先为了达到题目要求,就必须让每个机器人在坐标轴上的排列从 \(1\sim n\),或者是 \(n\sim 1\),只有这样才能是满足题目条件的。在此条件的基础上,我们去考虑移动的距离问题。因为在坐标轴上,我们的操作就是把 \(1\sim n\)编号的机器人移动每个指定点即可,而这个指定点是只要确定一个,就可以确定全部。我们可以设指定点为 \(x+d、x+2\times d、x+3\times d......\),那么我们就可以求出每个点移动的距离,然后可以求出带未知数 \(x\) 的最大移动值 \(maxn\) 和最小移动值 \(minn\)。然后我们考虑怎么让最大值的最小,并且最大值还是最大,很显然,我们可以通过 \(maxn-minn\) 求出最大值的最小值,而在减的过程中,x也减掉了。从而得到答案。需要注意,还需要考虑 \(n\sim 1\)排列,即把机器人的编号反过来即可。

代码:

ll a[maxn],b[maxn];
 
int main()
{
    ll n,m;
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        b[n-i+1]=a[i];
    }
    ll maxx=-INF,minx=INF;
    for(int i=1;i<=n;i++){
        maxx=max(maxx,a[i]-1ll*i*m);
        minx=min(minx,a[i]-1ll*i*m);
    }
    ll ans=maxx-minx;
    maxx=-INF,minx=INF;
    for(int i=1;i<=n;i++){
        maxx=max(maxx,b[i]-1ll*i*m);
        minx=min(minx,b[i]-1ll*i*m);
    }
    ans=min(ans,maxx-minx);
    if(ans%2==1){
        printf("%lld.5",ans/2);
    }else{
        printf("%lld.0",ans/2);
    }
}

H、Needle

题意:
给你三个数组 \(a、b、c\),问在这些数组中存在多少组 \((i,j,k)\) 满足 \(a[i]+c[k]=2\times b[j]\)

想法:

  • \(n\) 很大,暴力肯定会超时。考虑多项式乘法,把数组 \(a,b\) 各自作为两个多项式中 \(x\) 的系数,最后把两个多项式乘起来,然后只需要看 \(2\times b[j]\)作为次数在这个多项式中系数的值即可,系数为几,就有几种方案。

  • 对于多项式乘法,用 \(NTT\) 完成即可,也就是一到快速数论变换的裸题。

  • 需要注意的就是数组中的数的范围是 \(-30000\sim 30000\),我们要的多项式次数需要正数,因此给每个数加上 \(30000\) 即可。

代码:

const int N = 300010;
const int Mod = 998244353;
int n,m,L,R[N],g[N],a[N],b[N];
LL x[N],ci[N];
 
int gi()
{
  int x=0,res=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
  while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  return x*res;
}
 
inline int QPow(int d,int z)
{
  int ans=1;
  for(;z;z>>=1,d=1ll*d*d%Mod)
    if(z&1)ans=1ll*ans*d%Mod;
  return ans;
}
 
inline void NTT(int *A,int f)
{
  for(int i=0;i<n;++i)if(i<R[i])swap(A[i],A[R[i]]);
  for(int i=1;i<n;i<<=1){
    int gn=QPow(3,(Mod-1)/(i<<1)),x,y;
    for(int j=0;j<n;j+=(i<<1)){
      int g=1;
      for(int k=0;k<i;++k,g=1ll*g*gn%Mod){
	x=A[j+k];y=1ll*g*A[i+j+k]%Mod;
	A[j+k]=(x+y)%Mod;A[i+j+k]=(x-y+Mod)%Mod;
      }
    }
  }
  if(f==1)return;reverse(A+1,A+n);
  int y=QPow(n,Mod-2);
  for(int i=0;i<n;++i)A[i]=1ll*A[i]*y%Mod;
}
int main(){
    int m1,m2,m3,l=0;
    long long c1,c2;
    scanf("%d",&m1);
    for(int i=0;i<m1;++i){
        int num;
        cin>>num;
        a[num+30000]=1;
        c1=max(c1,1ll*num+30000);
    }
    scanf("%d",&m2);
    for(int i=0;i<m2;++i){
        scanf("%lld",&x[i]);
        x[i]+=30000;
    }
    scanf("%d",&m3);
    for(int i=0;i<m3;++i){
        int num;
        cin>>num;
        b[num+30000]=1;
        c2=max(c2,1ll*num+30000);
    }
    c1--;
    c2--;
    for(c2+=c1,n=1;n<=c2;n<<=1,++L);
    for(int i=0;i<n;++i)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
    NTT(a,1);NTT(b,1);
    for(int i=0;i<n;++i)a[i]=1ll*a[i]*b[i]%Mod;
    NTT(a,-1);
    //memset(ci,0,sizeof ci);
    long long ans=0;
    for(int i=0;i<m2;i++){
        ans+=1ll*a[x[i]*2];
    }
    cout<<ans;
    return 0;
}
posted @ 2021-01-27 20:09  hachuochuo  阅读(709)  评论(0编辑  收藏  举报