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