1. 程式人生 > 實用技巧 >2020杭電多校第六場題解

2020杭電多校第六場題解

2020 Multi-University Training Contest 6


施工中。。。

1001 Road To The 3rd Building

求得每個數的機率,得到相應的差分公式,然後求兩次差分即可。

#include<bits/stdc++.h>
#define ll long long
#define maxn 400010
#define mod 1000000007
using namespace std;
ll poow(ll x,ll y){
    ll bas=1;
    while(y){
        if(y%2) bas=bas*x%mod;
        x=x*x%mod;
        y/=2;
    }
    return bas;
}
ll po(ll x){
    return poow(x,mod-2);
}
ll inv[maxn],ans[maxn],a[maxn];
int main(){
    inv[0]=1;
    for(int i=1;i<200010;i++) inv[i]=po(i);
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]),ans[i]=0;
        for(int i=1;i<=n/2;i++){
            ans[1]+=inv[i];
            ans[i+1]-=inv[i];
            ans[n+2-i]-=inv[i];
            ans[1]+=inv[n+1-i];
            ans[i+1]-=inv[n+1-i];
            ans[n+2-i]-=inv[n+1-i];
            ans[1]%=mod;
            ans[i+1]%=mod;
            ans[n+2-i]%=mod;
        }
        if(n%2){
            ans[1]+=inv[(n+1)/2];
            ans[1]%=mod;
            ans[(n+1)/2+1]-=2*inv[(n+1)/2];
            ans[(n+1)/2+1]%=mod;
        }
        for(int i=2;i<=n;i++) ans[i]=(ans[i-1]+ans[i])%mod;
        for(int i=2;i<=n;i++) ans[i]=(ans[i-1]+ans[i])%mod;
        ll sum=0;
        for(int i=1;i<=n;i++) sum=(sum+ans[i]*a[i]%mod)%mod;
        while(sum<0) sum+=mod;
        sum=sum*inv[n]%mod*inv[n+1]%mod*2%mod;
        printf("%lld\n",sum);
    }
    return 0;
}

1002 Little Rabbit's Equation

純粹模擬,切忌輸出1(WA的教訓)。

#include<bits/stdc++.h>
#define ll long long
#define maxn 200010
#define mod 998244353
using namespace std;
char a[200];
int main(){
    map<char,int>mp;
    for(int i=0;i<10;i++){
        mp['0'+i]=i;
    }
    for(int i=0;i<6;i++){
        mp['A'+i]=10+i;
    }
    while(scanf("%s",a)!=EOF){
        int n=strlen(a);
        vector<int>s1,s2,s3;
        int cnt=0,ma=1;
        while(cnt<n){
            if(!mp.count(a[cnt])) break;
            s1.push_back(mp[a[cnt]]);
            ma=max(ma,mp[a[cnt]]);
            cnt++;
        }
        char pe=a[cnt++];
        while(cnt<n){
            if(!mp.count(a[cnt])) break;
            s2.push_back(mp[a[cnt]]);
            ma=max(ma,mp[a[cnt]]);
            cnt++;
        }
        cnt++;
        while(cnt<n){
            if(!mp.count(a[cnt])) break;
            s3.push_back(mp[a[cnt]]);
            ma=max(ma,mp[a[cnt]]);
            cnt++;
        }
        int ans=-1;
        for(int i=ma+1;i<=16&&ans==-1;i++){
            __int128 x=0,y=0,z=0;
            for(int j=0;j<s1.size();j++){
                x=x*i+s1[j];
            }
            for(int j=0;j<s2.size();j++){
                y=y*i+s2[j];
            }
            for(int j=0;j<s3.size();j++){
                z=z*i+s3[j];
            }
            if(pe=='+'){
                if(x+y==z) ans=i;
            }
            else if(pe=='-'){
                if(x-y==z) ans=i;
            }
            else if(pe=='*'){
                if(x*y==z) ans=i;
            }
            else if(pe=='/'){
                if(y*z==x) ans=i;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

1003 Borrow

dp+概率+組合數,還有注意某些情況有重複計算。

博主補完題後神志不清,暫時無法解釋原理。

#include<bits/stdc++.h>
#define ll long long
#define maxn 1000010
#define mod 998244353
using namespace std;
ll dp[maxn][2];
ll fac[maxn],inv[maxn],in2[maxn];
ll po(ll x){
	ll bas=1,y=mod-2;
	while(y){
		if(y%2) bas=bas*x%mod;
		x=x*x%mod;
		y/=2;
	}
	return bas;
}
ll C(int n,int m){
	return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main(){
	fac[0]=inv[0]=1;
	for(int i=1;i<maxn;i++){
		fac[i]=fac[i-1]*i%mod;
	}
	inv[maxn-1]=po(fac[maxn-1]);
	for(int i=maxn-2;i>=1;i--){
		inv[i]=inv[i+1]*(i+1)%mod;
	}
	dp[0][0]=0;
	ll p2=po(2);
	in2[0]=1;
	for(int i=1;i<maxn;i++){
		in2[i]=in2[i-1]*p2%mod;
	}
	for(int i=1;i<maxn;i++){
		dp[i][0]=2+dp[i-1][1];
		dp[i][1]=2+dp[i-2][0];
	}
	int t;
	scanf("%d",&t);
	while(t--){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		if((x+y+z)%3){
			printf("-1\n");
			continue;
		}
		if(x>y) swap(x,y);
		if(y>z) swap(y,z);
		if(x>y) swap(x,y);
		x=z-x,y=z-y;
		if(y==0||y==1){
			printf("%lld\n",dp[x][y]);
			continue;
		}
		ll ans=0;
		for(int i=x;i>=2;i--){
			if((x-i+y-1)%3==0&&(x-i+y-1)/3<=x-i&&(x-i+y-1)/3<=y-1){
				ll sum=(x-i+y-1)/3;
				ll num=x-i-sum;
				ans=(ans+(sum+dp[i][1])%mod*C(sum,num)%mod*in2[sum]%mod)%mod;
			}
			else if((x-i+y)%3==0&&(x-i+y)/3<=x-i&&(x-i+y)/3<=y){
				ll sum=(x-i+y)/3;
				ll num=x-i-sum;
				ll cu=C(sum,num);
				if(num!=0) cu-=C(sum-1,num-1);
				ans=(ans+(cu*in2[sum]%mod)*(sum+dp[i][0])%mod)%mod;
			}
		}
		for(int i=y;i>=2;i--){
			if((y-i+x-1)%3==0&&(y-i+x-1)/3<=y-i&&(y-i+x-1)/3<=x-1){
				ll sum=(x-i+y-1)/3;
				ll num=y-i-sum;
				ans=(ans+C(sum,num)*(sum+dp[i][1])%mod*in2[sum]%mod)%mod;
			}
			else if((x-i+y)%3==0&&(x-i+y)/3<=y-i&&(x-i+y)/3<=x){
				ll sum=(x-i+y)/3;
				ll num=y-i-sum;
				ll cu=C(sum,num);
				if(num!=0) cu-=C(sum-1,num-1);
				ans=(ans+(cu*in2[sum]%mod)*(sum+dp[i][0])%mod)%mod;
			}
		}
		while(ans<0) ans+=mod;
		printf("%lld\n",ans);
	}
	return 0;
}

1005 Fragrant numbers

賽時打表跑數小時,喜提WA。

賽後補題,區間DP,跑得飛快。

題目需要注意的無非就是一個區間中能組合出哪些數。

#include<bits/stdc++.h>
#define ll long long
#define maxn 400010
#define mod 1000000007
using namespace std;
int a[10]={1,1,4,5,1,4,1,9,1,9};
int pe[20][20][100010];
int dp[5010];
int sol(int l,int r){
	int sum=0;
	for(int i=l;i<=r;i++){
		sum=sum*10+a[(i-1)%10];
	}
	return sum;
}
int main(){
	memset(dp,-1,sizeof(dp));
	for(int i=1;i<=13;i++){
		pe[i][i][a[(i-1)%10]]=1;
	}
	for(int len=1;len<13;len++){
		for(int i=1;i+len<=13;i++){
			int j=i+len;
			if(len<4){
				int x=sol(i,j);
				if(x<=5000) pe[i][j][x]=1;
			}
			for(int mid=i;mid<j;mid++){
				for(int k=1;k<=5000;k++){
					if(pe[i][mid][k]==0) continue;
					for(int u=1;u<=5000;u++){
						if(pe[mid+1][j][u]==0) continue;
						if(k+u<=5000) pe[i][j][k+u]=1;
						if(k*u<=5000) pe[i][j][k*u]=1;
					}
				}
			}
		}
	}
	for(int i=13;i>=1;i--){
		for(int j=1;j<=5000;j++){
			if(pe[1][i][j]) dp[j]=i;
		}
	}
	int t;
	scanf("%d",&t);
	while(t--){
		int x;
		scanf("%d",&x);
		printf("%d\n",dp[x]);
	}
	return 0;
}

1006 Paperfolding

#include <bits/stdc++.h>
#pragma warning (disable:4996)
using namespace std;

typedef long long LL;
const int maxn = 1e5 + 5;
const LL mod = 1e9 + 7;
struct Line {
    int u, v;
    LL w;
}line[maxn * 2];
int f[maxn];
int find(int x) {
    while (x != f[x])
        x = f[x] = f[f[x]];
    return x;
}

typedef pair<int, LL>pii;
vector<pii> E[maxn];

int a[maxn];
LL n_size[maxn][2], sum[maxn][2];

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        int u, v;
        LL w = 1;
        for (int i = 1; i <= m; i++) {
            scanf("%d%d", &line[i].u, &line[i].v);
            w = w * 2 % mod;
            line[i].w = w;
        }

        int limit = n;
        for (int i = 1; i <= n; i++) {
            f[i] = i;
            E[i].clear();
        }
        for (int i = 1; i <= m; i++) {
            int eu = find(line[i].u);
            int ev = find(line[i].v);
            if (eu != ev) {
                f[eu] = ev;
                E[line[i].u].push_back(make_pair(line[i].v, line[i].w));
                E[line[i].v].push_back(make_pair(line[i].u, line[i].w));
                limit--;
                if (limit == 1)
                    break;
            }
        }

        LL ans = 0;
        function<void(int, int)> dfs;
        dfs = [&](int now, int fa) {
            n_size[now][0] = n_size[now][1] = 0;
            sum[now][0] = sum[now][1] = 0;
            n_size[now][a[now]] = 1;

            for (auto it : E[now]) {
                if (it.first == fa)
                    continue;
                dfs(it.first, now);
                n_size[now][0] += n_size[it.first][0];
                sum[now][0] = (sum[now][0] + sum[it.first][0] + n_size[it.first][0] * it.second % mod) % mod;
                n_size[now][1] += n_size[it.first][1];
                sum[now][1] = (sum[now][1] + sum[it.first][1] + n_size[it.first][1] * it.second % mod) % mod;
            }

            for (auto it : E[now]) {
                if (it.first == fa)
                    continue;
                ans=(ans+(sum[it.first][0] + n_size[it.first][0] * it.second %mod)%mod*(n_size[now][1] - n_size[it.first][1])%mod
                +(sum[it.first][1] + n_size[it.first][1] * it.second %mod)%mod*(n_size[now][0] - n_size[it.first][0])%mod)%mod;
            }
        };
        dfs(1, 0);

        printf("%lld\n", ans);
    }
    return 0;
}

1009 Divisibility

#include <bits/stdc++.h>
#pragma warning (disable:4996)
using namespace std;

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        long long b, x;
        scanf("%lld%lld", &b, &x);
        if (b <= x) printf("F\n");
        else if (b % x == 1) printf("T\n");
        else printf("F\n");
    }
    return 0;
}

1010 Expectation

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int maxn = 1e4 + 5;
const LL mod = 998244353;
struct Line {
    int u, v;
    LL w;
} line[maxn];

LL quickpow(LL m, LL p) {
    LL res = 1;
    while (p) {
        if (p & 1)
            res = res * m % mod;
        m = m * m % mod;
        p >>= 1;
    }
    return res;
}

namespace Matrix {
const int maxn = 105;
LL a[maxn][maxn];
LL ans;
void work(int n) {
    for (int i = 2, inv, tmp; i <= n; ++i) {
        for (int j = i + 1; j <= n; ++j)
            if (!a[i][i] && a[j][i]) {
                ans = -ans;
                swap(a[i], a[j]);
                break;
            }
        inv = quickpow(a[i][i], mod - 2);
        for (int j = i + 1; j <= n; ++j) {
            tmp = (LL)a[j][i] * inv % mod;
            for (int k = i; k <= n; ++k)
                a[j][k] = (a[j][k] - (LL)a[i][k] * tmp % mod) % mod;
        }
    }
}
LL slove(int n, int m, LL limit) {
    ans = 1;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            a[i][j] = 0;
    for (int i = 1; i <= m; ++i) {
        if (!(line[i].w & limit))
            continue;
        int x = line[i].u, y = line[i].v;
        a[x][x]++;
        a[y][y]++;
        a[x][y]--;
        a[y][x]--;
    }
    work(n);
    for (int i = 2; i <= n; ++i)
        ans = (LL)ans * a[i][i] % mod;
    return (ans % mod + mod) % mod;
}
} // namespace Matrix

int main() {

    int t;
    scanf("%d", &t);
    while (t--) {
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; i++)
            scanf("%d%d%lld", &line[i].u, &line[i].v, &line[i].w);

        LL ans = 0;
        for (int i = 0; i <= 31; i++)
            ans = (ans + (1 << i) % mod * Matrix::slove(n, m, (1 << i)) % mod) %
                  mod;
        LL inv = Matrix::slove(n, m, (LL(1) << 32) - 1);
        inv = quickpow(inv, mod - 2);
        ans = ans * inv % mod;
        printf("%lld\n", ans);
    }

    return 0;
}