zoukankan      html  css  js  c++  java
  • 10.28 模拟赛

    10.28 模拟赛

    A 排列

    写了一种不知道为啥正确的贪心方法。。

    巨难写的正解貌似没啥意义就丢在这里了。

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<set>
    using namespace std;
    #define MAXN 5006
    int n;
    int A[MAXN], B[MAXN], res[MAXN];
    multiset<int> S;
    int main() <%
        scanf("%d", &n);
        for( int i = 1 ; i <= n ; ++ i )
            scanf("%d",& A[i]);
        for( int i = 1 ; i <= n ; ++ i )
            scanf("%d",& B[i]);
        for (int i = 1; i <= n; i++)
            S.insert(B[i]);
        for (int i = n; i; i--) {
            auto it = S.upper_bound(A[i]);
            it = ( it == S.end() ? S.begin() : it );
            res[i] = *it;
    		S.erase(it);
        }
        for (int i = 1; i <= n; i++) {
            int pos = -1;
            for (int j = i + 1; j <= n; j++) {
                if (res[i] >= res[j]) continue;
                bool fuck = 0 , f1 = A[i] < res[i] ,  f2 = A[j] < res[j];
                fuck = ( ( !f1 ) and ( f2 && A[i] < res[j] ) ) or ( ( f1 ) and ( f2 && A[j] < res[i] ) ) or ( f1 and !f2 ) or ( !f1 and !f2 );
                if ( fuck && (pos == -1 || res[pos] < res[j]) ) pos = j;
            }
            if (pos != -1) swap(res[i], res[pos]);
        }
        for( int i = 1 ; i <= n ; ++ i ) printf("%d ", res[i]);
    %>
    

    B 分组

    首先按照s排序,这样极值一定是某一组选择的最靠后的减去最靠前的。

    然后考虑 $ dp[i][j][s] $ 表示前 $ i $ 个同学,到现在没有确定最大值的组 有 $ j $ 组,且目前一共的权值为 $ s $

    那么这个就很容易转移了,分三种情况转移:

    1. 第 $ i $ 个同学加入了前面的某一组,并且并不作为最大值。
    2. 第 $ i $ 个同学加入了前面的某一组,并且作为最大值(也就是结束了某一组)
    3. 第 $ i $ 个同学新成了一组

    但是由于我们权值是极差,是先减后加,这样转移并不能直接砍掉 $ s geq k $ 的情况。

    可以考虑先给原数组差分,然后每一组就是一段差分的和,并且这个差分显然是正的,就可以砍掉 $ s geq k $ 的情况了。

    实现有些细节,需要想一想。

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define int long long
    #define P 1000000007
    #define MAXN 506
    #define MAXK 1006
    int n , k;
    int s[MAXN] , dir[MAXN];
    long long dp[2][MAXN][MAXK];
    signed main() {
    	cin >> n >> k;
    	for( int i = 1 ; i <= n ; ++ i ) scanf("%lld",&s[i]);
    	sort( s + 1 , s + 1 + n );
    	for( int i = 1 ; i <= n ; ++ i ) dir[i] = s[i] - s[i - 1];
    	dp[0][0][0] = 1;
    	int cur = 0 , bac = 1;
    	for( int i = 1 ; i <= n ; ++ i ) {
    		cur ^= 1 , bac ^= 1;
    		for( int j = 0 ; j <= i ; ++ j ) {
    			for( int ss = 0 ; ss <= k ; ++ ss ) {
    				int& x = dp[cur][j][ss];
    				x = 0;
    				if( ss >= j * dir[i] ) x += 1ll * ( j + 1 ) * dp[bac][j][ss - j * dir[i]] , x %= P;
    				if( ss >= ( j - 1 ) * dir[i] && j ) x += dp[bac][j - 1][ss - ( j - 1 ) * dir[i]] , x %= P;
    				if( ss >= ( j + 1 ) * dir[i] ) x += 1ll * ( j + 1 ) * dp[bac][j + 1][ss - ( j + 1 ) * dir[i]] , x %= P;
    			}
    		}
    	}
    	int res = 0;
    	for( int i = 0 ; i <= k ; ++ i ) 
    		res += dp[cur][0][i] , res %= P;
    	cout << res << endl;
    }
    

    C 异或

    最开始想的是xor差分,实际上一开始就相对了,只是差分做错了

    考虑对于一个点,定义它的点权是它连出去的所有边的边权的xor和

    可以证明使得整个树变成0的充要条件就是所有点点权变为0,这个感觉和NOIP 2018 D1T1 很类似,证明也在题解有。

    所以每次改变的链就变成了单点修改,考虑链中间的某个点一定有两个与他相连的边被xor,就xor没了。

    然后可以贪心得做,最后每个边权要么剩下一个要么不剩下了,状压dp即可。

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    #define MAXN 100006
    
    int n;
    int head[MAXN] , to[MAXN << 1] , nex[MAXN << 1] , wto[MAXN << 1] , ecn;
    void ade( int u , int v , int w ) {
    	to[++ecn] = v , wto[ecn] = w , nex[ecn] = head[u] , head[u] = ecn;
    }
    int S[MAXN];
    void dfs( int u , int fa , int wfa ) {
    	S[u] = wfa;
    	for( int i = head[u] ; i ; i = nex[i] ) {
    		int v = to[i];
    		if( v == fa ) continue;
    		S[u] ^= wto[i];
    		dfs( v , u , wto[i] );
    	}
    }
    int num[16];
    int dp[1 << 16];
    int Just_DOIT( int st ) {
    	if( dp[st] != 0x3f3f3f3f ) return dp[st];
    	if( !st ) return 0;
    	for( int i = 1 ; i < 16 ; ++ i ) if( st & ( 1 << i ) ) {
    		int curst = ( st ^ ( 1 << i ) );
    		dp[st] = min( dp[st] , Just_DOIT( curst ) + 1 );
    		for( int j = 1 ; j < 16 ; ++ j ) if( j != i && ( st & ( 1 << j ) ) ) {
    			int cures = Just_DOIT( curst ^ ( 1 << j ) ^ ( 1 << ( j ^ i ) ) ) + ( ( st & ( 1 << ( j ^ i ) ) ) ? 2 : 1 );
    			dp[st] = min( dp[st] , cures );
    		}
    	}
    	return dp[st];
    }
    int main() {
    //	freopen("xor3.in","r",stdin);
    	cin >> n;
    	for( int i = 1 , u , v , w ; i < n ; ++ i ) {
    		scanf("%d%d%d",&u,&v,&w);
    		ade( u , v , w ) , ade( v , u , w );
    	}
    	dfs( 1 , 1 , 0 );
    	for( int i = 2 ; i <= n ; ++ i ) ++ num[S[i]];
    	int res = 0;
    	memset( dp , 0x3f , sizeof dp );
    	for( int i = 1 ; i < 16 ; ++ i ) 
    		res += num[i] / 2 , num[i] %= 2;
    	int sta = 0;
    	for( int i = 1 ; i < 16 ; ++ i ) if( num[i] )
    		sta |= ( 1 << i );
    	cout << res + Just_DOIT( sta ) << endl;
    }
    
  • 相关阅读:
    Delphi
    delphi trayIcon控件,如何实现窗口最小化的时候到系统托盘
    delphi2010自带 TTrayIcon 托盘图标控件使用方法
    通过例子来简单了解下TProgressBar的使用。 pas文件程序如下
    ORA-12154,ORA-12560解决过程
    博客备份小工具3
    各大招聘网站信息实时查询浏览
    IE7中使用Jquery动态操作name问题
    js问题杂记
    动态sql
  • 原文地址:https://www.cnblogs.com/yijan/p/1028comp.html
Copyright © 2011-2022 走看看