平时六测

 

第一题:抽屉原理,维护前缀和,出现一样的中间就可以了;

我看成了不能选一样的数(其实我觉得题意有歧义,也可能是我太久没学语文了),难度翻翻,以后要认真审题;

 

#include<bits/stdc++.h>
using namespace std;
const int M = 1000005;
bool dp[M];

int a[M], sum[M], ap[M];
int main(){
    freopen("set.in","r",stdin);
    freopen("set.out","w",stdout);
    int n, x, ans = -1, cnt = 0;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
    }
    memset(ap, -1, sizeof(ap));
    ap[0] = 0;
    for(int i = 1; i <= n; i++){
        sum[i] = (sum[i - 1] + a[i]) % n;
        if(ap[sum[i]] != -1) {
            printf("%d\n", i - ap[sum[i]]);
            for(int j = ap[sum[i]] + 1; j <= i; j++){
                printf("%d ", j);
            }
            break;
        }
        else ap[sum[i]] = i;
    } 
    
} 
View Code

 

 

 

第二题:空间问题,思路贪心,只要 max <= (n + 1)  /  2就可以全部选择;

不能用数组记录种类,采用抵消思想 ;

扫的时候记录一个id, cnt;

if  cnt = 0,    id = a[i], cnt = 1;

else if a[i] = id, cnt++

else cnt--;

最后跑出来的id是一个理想最大值;

如果 max > (n + 1) / 2, 那么id一定是种类最多的那个数, 这个采用抵消思想易证;

如果 max < (n + 1) / 2, id不一定是个数最多的那个数,但这不影响答案;

 

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int M = 1005;
int ct[M];
ll X[M], Y[M], Z[M]; 
int main(){
    freopen("read.in","r",stdin);
    freopen("read.out","w",stdout);
    int N, S, M, K, ret = 0, cnt = 0;
    scanf("%d%d", &M, &K);
    for(int i = 1; i <= M; i++)scanf("%d", &ct[i]), ret += ct[i];
    for(int i = 1; i <= M; i++)scanf("%lld", &X[i]);
    for(int i = 1; i <= M; i++)scanf("%lld", &Y[i]);
    for(int i = 1; i <= M; i++)scanf("%lld", &Z[i]);
    N = 0, S = (1 << K) - 1;
    ll qlst = -1;
    for(int i = 1; i <= M; i++){
        N++;
        if (cnt==0) qlst = X[i] ,cnt = 1;
        else if (X[i] == qlst) cnt++;
        else cnt--;
        
        ll lst = X[i];
        for(int j = 1; j < ct[i]; j++){
            lst = (lst * Y[i] + Z[i]) & S;
            N++;
            if (cnt==0) qlst = lst ,cnt = 1;
            else if (lst == qlst) cnt++;
            else cnt--;
        }
    }
    
    cnt = 0;
    N = 0, S = (1 << K) - 1;
    for(int i = 1; i <= M; i++){
        N++;
        ll lst = X[i];
        if(qlst == X[i]) cnt++;
        for(int j = 1; j < ct[i]; j++){
            lst = (lst * Y[i] + Z[i]) & S;
            N++;
            cnt += (lst == qlst); 
        }
    }
    if(cnt > (ret + 1)/2) printf("%d\n", cnt - (ret - cnt) - 1);
    else puts("0");
    
    
}
View Code

 

 

 

第三题:Trie树, 按照每个人的得分建一棵深度为m的Trie树;

 我们在Trie树上跑一个人积分的总和, 我们先按原数跑,假设现在的深度是dep,他当前排在前面,那么当 j 的这一位(dep位)改变时,这颗子树中每个排名都会整体往后降size[now]位, 而内部的相对排名是不变的;

我们记录P为当前节点中积分和 P = a1^2 + a2^2 + a3^2 +……

令S= siz[now], 那么另一个节点 P = (a1 + S) ^2 + (a2 + S)^2 + (a3 + S)^2 + ……

我们合并子树 P = P + P + (a1 + a2 + a3 + ……) * 2 * S + S*S * 2^(dep - 1)   (这个节点下有(2^(dep-1))场比赛;

用 sum = a1 + a2 + a3 + ……

所以 sum = sum * 2 + S * 2^(dep-1), P = 2 * P + 2 * S * sum + S*S * 2^(dep - 1)

 

#include<bits/stdc++.h>
using namespace std;
#define ss siz[ch[now][t^1]]
#define ll long long
const int M = 200005, ME = 5*1e6;
const ll mod = 1e9 + 7;
int a[M], tot;
ll bin[M], siz[ME];
int ch[ME][2], n, m;

void insert(int x){
    int now = 0;
    for(int i = m; i >= 1; i--){
        int t = bin[i-1] & x ? 1 : 0;
        if(!ch[now][t]) ch[now][t] = ++tot;
        now = ch[now][t];
        siz[now]++;
    }
}
struct Node{ll sum, q;}; 
Node query(int x, int dep, int now){
    if(!dep) return (Node) {0, 0};
    int t = bin[dep - 1] & x ? 1 : 0;
    Node rs = query(x, dep - 1, ch[now][t]);
    ll sum = (rs.sum * 2 % mod + ss * bin[dep - 1] % mod) % mod;
    ll q = (rs.q * 2 % mod + 2 * rs.sum * ss % mod + ss * ss % mod * bin[dep - 1] % mod ) % mod;
    
    return (Node) {sum, q};
}
int main(){
    freopen("race.in","r",stdin);
    freopen("race.out","w",stdout);
    
    scanf("%d%d", &n, &m);
    bin[0] = 1;
    for(int i = 1; i <= 31; i++) bin[i] = (bin[i - 1] << 1) % mod;
    for(int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
        insert(a[i]); 
    } 
    ll ans = 0;
    for(int i = 1; i <= n; i++){
        Node p = query(a[i], m, 0);
        //printf("%lld %lld\n", p.sum, p.q);
        ans = ans ^ p.q;
    }
    printf("%lld\n", ans);
} 
View Code

 

posted @ 2018-09-25 17:20  Ed_Sheeran  阅读(173)  评论(0编辑  收藏  举报