1. 程式人生 > 實用技巧 >2020hdu多校第六場比賽及補題

2020hdu多校第六場比賽及補題

1009Divisibility

題意搞半天才搞懂,把一個詞翻譯了一下,原來是命題的意思,我以為是一個定義。。

還是隊友告訴我我才理解的題意

就是一個命題:如果任意一個b進位制數,如果它的每位數加起來能被 x 整除,那麼它也可以被 x 整除

就比如任意一個10進位制數,如果它的每一位數加起來能被 3 整除,那麼它就能被 3 整除,命題為真

但任意一個10進位制數,如果它的每一位數加起來能被4整除,它不一定能被4整除,命題就為假

為什麼b=10時,x=3時,會有這個性質呢

這是因為10≡1(mod3),100≡1(mod3),1000≡1(mod3)....,46374≡(40000+6000+300+70+4)≡(4+6+3+7+4) (mod3)

(這個原理我很早以前就知道的)

顯而易見,就是任意一個數左移一位後要同餘它本身,左移一位就相當於乘以b,也就是要滿足b≡1(mod x)

#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
	int T;
	long long b,x;
	cin>>T;
	while(T--){
		cin>>b>>x;
		if((b-1)%x==0) cout<<"T"<<endl;
		else cout<<"F"<<endl;
	}
	return 0;
 } 

  

1002Little Rabbit's Equation

進位制模擬題,感覺有點麻煩的模擬,還好隊友幫我過了這題,強

#include <bits/stdc++.h>
using namespace std;
#define int long long
// const int MAXN = ;
// const int MOD = ;
// const int INF = ;
// const double eps = ;
// const int DIRX[] = {};
// const int DIRY[] = {};
string str;
char op;
string num[5];
int dci[5];

void getnum()
{
    int cnt = 1;
    num[1] = "";
    num[2] = "";
    num[3] = "";
    for (int i = 0; i < str.length(); ++i)
    {
        if (str[i] == '=')
        {
            cnt++;
            continue;
        }
        else if (str[i] == '+' || str[i] == '-' 
                || str[i] == '*' || str[i] == '/')
        {
            cnt++;
            op = str[i];
            continue;
        }
        else
        {
            if (str[i] >= '0' && str[i] <= '9')
                num[cnt] += (char)(str[i] - '0' + 1);
            else
                num[cnt] += (char)(str[i] - 'A' + 11);
        }
    }
    if (op == '-')
    {
        op = '+';
        swap(num[1], num[3]);
    }
    if (op == '/')
    {
        op = '*';
        swap(num[1], num[3]);
    }
}

int32_t main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    while (cin >> str)
    {
        getnum();
        bool flg = false;
        for (int i = 2; i <= 16; ++i)
        {
            bool ok = false;
            for (int j = 1; j <= 3; ++j)
            {
                dci[j] = 0;
                int tmp = 1;
                for (int k = num[j].length() - 1; k >= 0; --k)
                {
                    // cout << (int)num[j][k] << " ";
                    if (num[j][k] - 1 >= i)
                    {
                        ok = true;
                        break;
                    }
                    dci[j] += (num[j][k] - 1) * tmp;
                    tmp *= i;
                }
                if (ok)
                    break;
            }
            // cout << dci[1] << " " << dci[2] << " " << dci[3] << endl;
            if (ok)
                continue;
            if (!ok && op == '+')
            {
                if (dci[1] + dci[2] == dci[3])
                {
                    flg = true;
                    // cout << dci[1] << "+" << dci[2] << "=" << dci[3] << endl;
                    cout << i << endl;
                }
            }
            if (!ok && op == '*')
            {
                if (dci[1] * dci[2] == dci[3])
                {
                    flg = true;
                    // cout << dci[1] << "*" << dci[2] << "=" << dci[3] << endl;
                    cout << i << endl;
                }
            }
            if (flg)
                break;
        }
        if (!flg)
            cout << -1 << endl;
    }
    return 0;
}

  

1001Road To The 3rd Building

有 n 個數,要在[1,n]裡任選一個區間,區間的價值=區間內所有數之和 / 區間長度,求價值的期望是多少

思路:求每個數對最終價值的期望的貢獻

假設有五個數,

若選擇的區間長度為5,這五個數各自貢獻的區間數為 1 1 1 1 1

若選擇的區間長度為4,這五個數各自貢獻的區間數為 1 2 2 2 1

若選擇的區間長度為3,這五個數各自貢獻的區間數為 1 2 3 2 1

若選擇的區間長度為2,這五個數各自貢獻的區間數為 1 2 2 2 1

若選擇的區間長度為1,這五個數各自貢獻的區間數為 1 1 1 1 1

就是這個規律

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int MAXN = 2e5+7;
const long long MOD = 1e9+7;
long long s[MAXN];
long long th[MAXN];
long long inv[MAXN];

long long qpow(long long n,long long p){
	long long ret = 1;
    for (; p; p >>= 1, n = n * n % MOD)
        if (p & 1)
            ret = ret * n % MOD;
    return ret;
}
long long mod_inv(long long a) {
    return qpow(a,MOD - 2);
}
void pre(){
	inv[1] = 1;
    for (int i = 2; i <= 2e5; ++i)
        inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
    for(int i = 1;i <= 2e5; i++){
    	th[i] = (th[i-1] + inv[i]) % MOD;
    }
}
int main()
{
	int T, n;
	pre();
	cin >> T;
	while(T--){
		cin >> n;
		for(int i = 1;i <= n;i++){
			scanf("%lld",&s[i]);
		}
		long long fz = 0, fm;
		long long tt = 0;
		for(int i = 1;i * 2 <= n;i++){
			s[i] += s[n-i+1];
			s[i] %= MOD;
			tt += th[n-i+1] - th[i-1];
			tt = (tt % MOD + MOD) % MOD;
			fz = (fz + s[i] * tt) % MOD;
		}
		if(n % 2){
			tt += inv[n/2+1];
			tt = (tt % MOD + MOD) % MOD;
			fz = (fz + s[n/2+1] * tt) % MOD;
		}
		fm = (long long)n * ((long long)n+1) / 2 % MOD;//n沒有強制轉換成long long啊啊 
		long long ans = fz * mod_inv(fm) % MOD;
		cout<<ans<<endl;
	}
	return 0;
} 

  

n沒有強制轉換成long long wa了挺久qwq

1006A Very Easy Graph Problem

給n個點,m條邊,每個點有0,1兩種狀態,要求所有0點到所有1點的最短路的長度之和

給的這m條邊滿足第 i 條邊的長度為2^i

根據邊長度的性質,可以知道如果A點連了長度為2,4,8,16的邊到B,又連了條直接從A到B的邊,但這邊的長度為32,不能為最短路

推出一個結論,後面加的邊不可能更新已有的最短路,這個邊就忽略掉

這樣就像一個並查集一樣,把這個圖變成若干棵樹,然後我就在這些樹上進行樹形dp

然後我寫了個dfs就MLE了...

直到比賽結束我還是MLE

現在才發現原來我並查集寫炸了,死迴圈了。。。。

然後並查集改好了,還是wa了,手推樣例才發現,我那樹形dp的方法是錯的,要直接dfs一遍每條邊的貢獻就是這條邊的長度*(其一端0點數*另一端1點數+另一端0點數*其一端1點數)

終於過了xd

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
const int MAXN = 1e5+7;
const int MAXM = 2e5+7; 
const long long MOD = 1e9+7;
int a[MAXN];
long long llo[MAXM];

struct EDGE{
	int to, w ,next;
}edge[MAXN*2];
int head[MAXN],tot;

void add(int u,int v,int w){
	tot++;
	edge[tot].to = v;
	edge[tot].w = w;
	edge[tot].next = head[u];
	head[u] = tot;
}

int n,m;
long long ans;

int par[MAXN];
int find(int x){
    if(par[x] == x) return x;
    return par[x] = find(par[x]);
}

void pre(){
    llo[0] = 1;
    for(int i = 1;i <= 2e5;i++){
        llo[i] = llo[i-1] << 1;
        llo[i] %= MOD;
    }
}

int son0[MAXN],son1[MAXN];
long long edg[MAXN]; 
void dfs(int st,int f){
    son0[st] = son1[st] = 0;
    if(a[st] == 0) son0[st]++;
    else son1[st]++;
    for(int i = head[st];i ;i = edge[i].next){
        int po = edge[i].to;
        if(po == f) continue;
        long long lo = edge[i].w;
        lo = llo[lo];
        edg[po] = lo;
        dfs(po,st);
        son0[st] += son0[po];
        son1[st] += son1[po];
    }
}

int main()
{
	//freopen("1.in","r",stdin);
    int T;
    pre();
    cin >> T;
    int u,v;
    while(T--){
        cin >> n >> m;
        ans = 0;
        tot = 0;
        for(int i = 1;i <= n; i++) {        
            scanf("%d",&a[i]);
            par[i] = i;
            head[i] = 0;
        }
        for(int i = 1;i <= m; i++) {
            scanf("%d%d",&u,&v);
            int fu = find(u), fv = find(v);
            if(fu == fv) continue;
            else{
                par[fu] = fv;
                add(u,v,i);
                add(v,u,i);
            }
        }
        long long res;
        for(int i = 1;i <= n;i++){
            if(par[i] == i) dfs(i,0);  
        }
        for(int i = 1;i <= n;i++){
        	if(find(i)!=i){//不能寫成if(par[i]!-=i)因為par[i]並不一定直接連到根節點! 
        		long long ct = 0;
        		ct = 
				(long long)son1[i] * (  (long long)son0[par[i]] - (long long)son0[i]  ) + 
				(long long)son0[i] * (  (long long)son1[par[i]] - (long long)son1[i]  ) ;
				ans += edg[i] * ct;
				ans %= MOD;
			}
		}
        cout << ans << endl;
     }
    return 0;
}