• 2020hdu多校第五场比赛及补题


    1009 Paperfolding

    把一张矩形纸折n次,每次折可以从上往下折,或从下往上折,或从左往右折,或从右往左折

    这样一共有4^n种折法,折好后再把纸横切一刀,竖切一刀,再把纸展开,问展开后期望是多少张纸

    看起来好难的一题,比赛刚开始的时候,我还没读完题时,旁边的人都开始折纸了,我想:这题真的要动手折纸吗?然而我开始分析的时候,就忍不住开始折纸了2333

    分析出来后就不难了

    分析:

    • 从上往下折等价于从下往上折,从左往右折等价于从右往左折,自己拿张纸折几下,靠直觉得出这个结论
    • 自己折折纸,可以发现从左往右折a次,从上往下折b次,最后展开是((1<<a)+1)*((1<<b)+1)张纸(我找的规律,没去证明,就感觉是这样)

    计算:

    一共2^n种折法,分母就是2^n,

    从左往右一共折a次,从上往下一共折n-a次的情况是C(n,a)种(我还不会打数学符号啊啊啊),贡献为C(n,a)*((1<<a)+1)*((1<<(n-a))+1)

    检验一下,a的范围是0到n,C(n,0)+C(n,1)+C(n,2)+...+C(n,n)= 2^n种

    分子就是把C(n,a)*((1<<a)+1)*((1<<(n-a))+1)累加起来(a从0到n)

    C(n,a)*((1<<a)+1)*((1<<(n-a))+1) =       C(n,a) * [  (1<<n) + (1<<a) + (1<<(n-a)) + 1] = [C(n,a)*(1<<n)] + [C(n,a)*(1<<a)] + [C(n,a)*(1<<(n-a))] + [C(n,a)]

    [C(n,a)*(1<<n)] 累加起来等于 4^n,除以分母后等于 2^n

    [C(n,a)*(1<<a)]累加起来等于(2+1)^n = 3^n,除以分母后等于 3^n * inv(2^n)

    [C(n,a)*(1<<(n-a))]累加起来,根据对称性,它等于[C(n,a)*(1<<a)]

    [C(n,a)]累加起来等于2^n ,除以分母后等于1

    #include<iostream>
    #include<algorithm>
    using namespace std;
    const long long MOD = 998244353;
    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 inv(long long a) {
        return qpow(a, MOD - 2);
    }
    int main()
    {
        int T;
        long long n;
        cin>>T;
        while(T--){
            scanf("%lld",&n);
            long long res, tt, ni;
            res = qpow(2,n);
            tt = 2*qpow(3,n);
            ni = inv(res);
            tt = tt * ni % MOD;
            res += tt + 1;
            res %= MOD;
            printf("%lld\n",res);
        }
        return 0;
    }
    

      

    1001 Tetrahedron

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    const int MAXN = 6e6 + 7;
    const int MOD = 998244353;
    // const int INF = ;
    // const int DIRX[] = {};
    // const int DIRY[] = {};
    
    int ept[MAXN];
    
    inline int getpow(int a, int b)
    {
        int ret = 1;
        for (; b; b >>= 1, a = a * a % MOD)
            if (b & 1)
                ret = ret * a % MOD;
        return ret;
    }
    
    void pre()
    {
        int tmp = 0;
        for (int i = 1; i <= 6e6; ++i)
        {
            tmp += getpow(i * i % MOD, MOD - 2);
            tmp %= MOD;
            ept[i] = tmp;
        }
    }
    
    int T;
    int n;
    int ans;
    
    int32_t main(void)
    {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        pre();
        cin >> T;
        while (T--)
        {
            cin >> n;
            ans = (3 * ept[n] % MOD) * getpow(n, MOD - 2) % MOD;
            cout << ans << endl;
        }
        return 0;
    }
    

      

    1003 Boring Game

    很恶心的一题,折叠3次的情况我根本画不出,这题耗了很长时间,差不多3小时的时候,大家都A不出题,这时突然有个队大叫A了!A了!然后我马上看下榜单,并没有什么变化,学长问他们哪题A了,他们说样例A了...xswl

    关键是模拟构造order数组,折2次及以上是有构造规律的,折1次的情况是特判

    #include<iostream>
    #include<algorithm>
    #include<cstdio> 
    using namespace std;
    int zheng[203][2050];
    int fan[203][2050];
    int order[2050],neworder[2050];
    int main()
    {
    	int T,n,k,cnt;
    	cin>>T;
    	while(T--){
    		cin>>n>>k;
    		cnt = 0;
    		for(int i = (1<<k);i;i--){
    			order[i] = 0;
    			cnt++;
    			if(i % 2) {//正 
    				for(int j = 1;j <= n;j++){
    					scanf("%d%d",&zheng[j][cnt],&fan[j][cnt]);
    				}
    			}
    			else{//反 
    				for(int j = n;j ;j--){
    					scanf("%d%d",&fan[j][cnt],&zheng[j][cnt]);
    				}
    			}
    		}
    		int len = 2;
    		order[1] = 1 ;order[2] = 2;//折2次的情况把折1次的情况包括进去了,初始化就直接初始成折2次的情况 
    		for(int e = 2;e <= k;e++){//从折2次开始构造 
    			for(int i = 1;i<=len;i++){
    				int x = order[len-i+1];
    				if(x%2) neworder[i] = x * 2;
    				else neworder[i] = x * 2 - 1; 
    			}
    			for(int i = len+1;i<=len*2;i++){
    				int x = order[i-len];
    				if(x%2) neworder[i] = x * 2 - 1;
    				else neworder[i] = x * 2;
    			}
    			len *= 2;
    			for(int i = 1;i <= len;i++){
    				order[i] = neworder[i];
    				//cout<<order[i]<<" ";
    			}
    			//cout<<endl;
    		}
    		for(int i = 1;i<=n;i++){
    			for(int j = 1;j <= (1<<k) ;j++){
    				printf("%d ",zheng[i][order[j]]);
    			}
    			//printf("\n");
    			for(int j = 1;j < (1<<k) ;j++){
    				printf("%d ",fan[i][order[j]]);
    			}
    			printf("%d",fan[i][order[(1<<k)]]);
    			if(i!=n) printf(" ");	
    			//printf("\n");
    		}
    		printf("\n");
    	}
    	return 0;
    }
    

      

    PE了2发,惊了,末尾多输出空格会PE

    1012 Set1

    一个集合为1,2,3,4,...,n ,n是奇数,每次操作是集合中会删掉一个最小的数,然后随机选一个数删除,重复进行这集合个操作直到集合中只剩下最后一个数

    求1,2,3....分别为最后一个数的概率

    分母 = 总的操作方案数 = (n-1)*(n-3)*(n-5)*...*2 = ((n-1)/2)! * 2^((n-1)/2)

    1,2,3,...(n-1)/2是不可能成为最后一个数的

    第 i 个数,在其后 n - i 个数必须要删完,也就是分子 = (n-i)! * 某个东西

    比赛的时候就是这个某个东西算不来

    关键的一点就是,在删这n - i个数中的某个数a时,在前 i - 1个数中删掉了剩余的最小的数b,这n - i 个a对应n - i个b,而这n - i 个 b 可以是前 i - 1个数里选出的 n - i 个数的任意组合,情况有C(i - 1,n - i)种,这 n - i 个 b确定后,前 i - 1 个数里剩下的数就可以任意删了

    假设剩下的数有 re 个,任意删的方案数 = (n-1)*(n-3)*(n-5)*...*1 = (n-1)! / [(n-2)*(n-4)*...*2] = (n-1)! / { [(n-2)/2]! * 2^[(n-2)/2] } 

    某个东西 = C(i - 1,n - i) * (n - 1)! / { [(n-2)/2]! * 2^[(n-2)/2] } 

    主要就是没想到后n - i 个数对应前 i - 1个数中 n - i个数

    #include<iostream>
    #include<algorithm> 
    using namespace std;
    const int MAXN = 5e6+7;
    const long long MOD = 998244353; 
    long long fact[MAXN];
    long long inv[MAXN];
    void pre(){
    	fact[0] = 1;
    	for(int i = 1;i <= 5e6;i++)
    		fact[i] = fact[i-1] * i % MOD;
    	inv[1] = 1;
        for (int i = 2; i <= 5e6; i++)
            inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
        inv[0] = 1;
        for (int i = 1; i <= 5e6; i++)
            inv[i] = inv[i] * inv[i - 1] % MOD;
    }
    
    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);
    }
    long long C(int n,int m){
    	return fact[n]*inv[m]%MOD*inv[n-m]%MOD;
    }
    int main()
    {
    	int T, n;
    	pre();
    	cin>>T;
    	long long MODINV2 = mod_inv(2);
    	while(T--){
    		cin>>n;
    		if(n == 1) {
    			printf("1\n");
    			continue;
    		}
    		long long fm, invfm;
    		fm = qpow(2,n/2)*fact[n/2]%MOD;
    		invfm = mod_inv(fm);
    		int pos = n / 2 + 1;
    		int re = 0;
    		long long tt = 1;
    		for(int i = 1;i < pos;i++) printf("0 ");
    		for(;pos <= n;pos++){
    			long long res = fact[n-pos];
    			res = res * C(pos-1,n-pos) % MOD;
    			long long ret ;
    			if(!re) ret = 1;
    			else{
    				ret = fact[re-1] * inv[(re-2)/2] % MOD * tt % MOD;
    				tt = tt * MODINV2 % MOD;
    			}
    			res = res * ret % MOD * invfm % MOD;
    			re += 2;
    			if(pos < n)printf("%lld ",res);
    			else printf("%lld\n",res);
    		}
    	}
    	return 0;
    } 
    

      

  • 相关阅读:
    《Expert .NET 2.0 IL Assembler》 译者笔记 2
    游戏大厅升级日记 第2天
    《Metadata Tables》 Authors
    随便写写,蛮有趣的
    《Metadata Tables》 Introduction
    Oracle跨数据库的数据操作
    要换工作环境了
    javascript中几种操作打印的方法
    Datagrid中实现单选功能
    C#中利用Oracle事务删除表
  • 原文地址:https://www.cnblogs.com/ruanbaitql/p/13560700.html
Copyright © 2020-2023  润新知