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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM