2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛

参考我的博客杜教筛

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn=1000010;
const ll mod=1e9+7;
int prime[maxn],f[maxn],sum[maxn],cnt;
bool vis[maxn];

int pow_mod(int a,int b) {
    int res = 1;
    while (b) {
        if (b & 1) res = 1ll*res * a % mod;
        b >>= 1;
        a = 1ll*a * a % mod;
    }
    return res;
}

void init() {
    int N = maxn - 1;
    f[1] = 1;
    sum[1] = 1;
    for (int i = 2; i <= N; i++) {
        if (!vis[i]) {
            prime[cnt++] = i;
            f[i] = i - 1;
        }
        for (int j = 0; j < cnt && 1ll*prime[j] * i <= N; j++) {
            vis[prime[j] * i] = 1;
            if (i % prime[j] == 0) {
                f[i * prime[j]] = 1ll*f[i] * prime[j]%mod;
                break;
            }
            f[i * prime[j]] = 1ll*f[i] * f[prime[j]]%mod;
        }
        sum[i]=(sum[i-1]+1ll*f[i]*i%mod)%mod;
    }
}
unordered_map<int,int>ma;
int inv6=pow_mod(6,mod-2);
int Go(int n) {
    if (n < maxn) return sum[n]%mod;
    if (ma[n]!=0) return ma[n];
    int ans = 1ll * (n + 1) * n % mod * (2 * n + 1) % mod * inv6 % mod;
    for (int i = 2; i <= n; ){
        int j = n / (n / i);
        ans = (ans + mod - (1ll * (j + 1) * j / 2 - 1ll * i * (i - 1) / 2) % mod * Go(n / i) % mod) % mod;
        i = j + 1;
    }
    return ma[n] = ans;
}
int main() {
    init();
    int _;
    scanf("%d", &_);
    int inv2 = pow_mod(2, mod - 2);
    while (_--) {
        int n,a,b;
        scanf("%d%d%d", &n, &a, &b);
        printf("%d\n", (Go(n) - 1 + mod) % mod * inv2 % mod);
    }
}

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
int T;
int n;
ll k;
const int maxn=1e5+5;
priority_queue<ll,vector<ll>,less<ll> >q;
ll c[maxn];
int main()
{
    cin>>T;
    while(T--)
    {
        scanf("%d%lld",&n,&k);
        while(!q.empty())q.pop();
        ll sum=0;
        for(register int i=1;i<=n;++i){
            scanf("%lld",c+i);
            q.push(c[i]);
            sum+=c[i];
        }
        sort(c+1,c+1+n);
        ll tot=0;
        for(register int i=2;i<=n;++i){
            tot+=c[i]/k;
        }
        if(tot>=n-1){
            printf("%lld\n",sum+k);
            continue;
        }
        sum+=n*k;
        for(register int i=1;i<n;++i){
            ll cur=q.top();
            q.pop();
            if(cur>k){
                sum-=k;
                cur-=k;
            }
            else{
                sum-=cur;
                cur=0;
            }
            q.push(cur);
        }
        printf("%lld\n",sum);
    }
    return 0;
} 

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;

char s[12][10000][10000];

void dfs(int id,int cur){
    if(id>10)return;
    for(register int i=1;i<=cur;++i){
        for(register int j=1;j<=cur;++j){
            s[id][i][j]=s[id-1][i][j];
        }
    }
    for(register int i=1;i<=cur;++i){
        for(register int j=cur+1;j<=2*cur;++j){
            s[id][i][j]=s[id-1][i][j-cur];
        }
    }
    for(register int i=cur+1;i<=2*cur;++i){
        for(register int j=1;j<=cur;++j){
            if(s[id-1][i-cur][j]=='C')s[id][i][j]='P';
            else s[id][i][j]='C';
        }
    }
    for(register int i=cur+1;i<=2*cur;++i){
        for(register int j=cur+1;j<=2*cur;++j){
            s[id][i][j]=s[id-1][i-cur][j-cur];
        }
    }
    dfs(id+1,cur*2);
}
int T,n;
int fast_pow(int a,int b){
    int res=1;
    while(b){
        if(b&1)res=res*a;
        a=a*a;
        b>>=1;
    }
    return res;
}
int main() {
    s[1][1][1]='C';
    s[1][1][2]='C';
    s[1][2][1]='P';
    s[1][2][2]='C';
    dfs(2,2);
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        int cur=n;
        n=fast_pow(2,n);
        //cout<<"***"<<endl;
        for(register int i=1;i<=n;++i){
            for(register int j=1;j<=n;++j){
                printf("%c",s[cur][i][j]);
            }
            printf("\n");
        }
    }
    return 0;
}

首先询问许多子串的这种问题应该联想到后缀数组,然后我们发现对于后缀数组中的排序(sa[i]表示下标为i的后缀的排名,rk[i]表示排名为i的后缀的下标),每个后缀串与子串的最长公共前缀为该子串的串是连续的,所以我们只要求出这段连续排名的区间(因为在这里的对于子串的最长公共前缀具有单调性,用st表预处理出每个区间的最长公共前缀长度,用二分check即可),然后在这段区间上询问第k大sa[i]的数即可。

我们考虑,一个子串必定是某个后缀的前缀。

排序相邻的后缀他们的前缀一定最相似。

所以全部的一种子串必定是一些排序相邻的后缀的公共前缀。

从l开始的子串,则从rank[l]开始看,两侧height保证大于子串长度,能延伸多长,则证明有多少个这种子串。

我们用ST表维护出height的最小值,然后通过最小值二分即可,边界有些棘手。

然后我们就得到了一个height不小于子串长度的连续区间,这个区间是以原后缀的字典序排序的。

而同时,sa数组下标为排序,值为原串位置。

所以我们对这个区间在sa数组上做主席树,求第k大,即为第k个子串出现的位置。

#include <bits/stdc++.h>

using namespace std;

const int maxn=110010;
int t1[maxn],t2[maxn],c[maxn];

bool cmp(int *r,int a,int b,int l) {
    return r[a] == r[b] && r[a + l] == r[b + l];
}

void da(char str[],int sa[],int rank[],int height[],int n,int m) {
    int i, j, p, *x = t1, *y = t2;
    for (i = 0; i <= m; i++) c[i] = 0;
    for (i = 1; i <= n; i++) c[x[i] = str[i]]++;
    for (i = 2; i <= m; i++) c[i] += c[i - 1];
    for (i = n; i >= 1; i--) sa[c[x[i]]--] = i;
    for (j = 1; j <= n; j <<= 1) {
        p = 0;
        for (i = n - j + 1; i <= n; i++) y[++p] = i;
        for (i = 1; i <= n; i++) if (sa[i] > j) y[++p] = sa[i] - j;
        for (i = 1; i <= m; i++) c[i] = 0;
        for (i = 1; i <= n; i++) c[x[y[i]]]++;
        for (i = 2; i <= m; i++) c[i] += c[i - 1];
        for (i = n; i >= 1; i--) {
            sa[c[x[y[i]]]--] = y[i];
            y[i] = 0;
        }
        swap(x, y);
        p = 1;
        x[sa[1]] = 1;
        for (i = 2; i <= n; i++) x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p : ++p;
        if (p == n) break;
        m = p;
    }

    int k = 0;
    for (i = 1; i <= n; i++) rank[sa[i]] = i;
    for (i = 1; i <= n; i++) {
        if (rank[i] == 1) continue;
        if (k) k--;
        j = sa[rank[i] - 1];
        while (j + k <= n && str[i + k] == str[j + k]) k++;
        height[rank[i]] = k;
    }
}

char str[maxn];
int sa[maxn],rk[maxn],height[maxn],n,q,st[maxn][20];
void build_st() {
    for (int i = 1; i <= n; i++) st[i][0] = height[i];
    for (int k = 1; k <= 19; k++) {
        for (int i = 1; i + (1 << k) - 1 <= n; i++) {
            st[i][k] = min(st[i][k - 1], st[i + (1 << k - 1)][k - 1]);
        }
    }
}
int lcp(int a,int b){
    a=rk[a];
    b=rk[b];
    if (a>b) swap(a,b);
    if (a==b) return n-sa[a];
    int t=log2(b-a);
    return min(st[a+1][t],st[b-(1<<t)+1][t]);
}

struct node
{
    int l,r,sum;
} hjt[maxn*40];
int cnt,root[maxn*40];

void insert(int l,int r,int pre,int &now,int p)
{
    hjt[++cnt]=hjt[pre];
    now=cnt;
    hjt[now].sum++;
    if (l==r)
    {
        return;
    }
    int mid=(l+r)>>1;
    if (p<=mid)
    {
        insert(l,mid,hjt[pre].l,hjt[now].l,p);
    }
    else
    {
        insert(mid+1,r,hjt[pre].r,hjt[now].r,p);
    }
}

int query(int l,int r,int L,int R,int k)
{
    if (l==r)
        return l;
    int mid=(l+r)>>1;
    int tmp=hjt[hjt[R].l].sum-hjt[hjt[L].l].sum;
    if (k<=tmp)
    {
        return query(l,mid,hjt[L].l,hjt[R].l,k);
    }
    else
    {
        return query(mid+1,r,hjt[L].r,hjt[R].r,k-tmp);
    }
}

vector<int>v;
void init(){
    cnt=0;
    v.clear();
    for (int i=0;i<=n;i++) {
        root[i]=hjt[i].l=hjt[i].r=hjt[i].sum=0;
    }
}

int getid(int x)
{
    return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}

int main() {
    int _;
    scanf("%d", &_);
    while (_--) {
        scanf("%d%d", &n, &q);
        scanf("%s", str + 1);
        da(str, sa, rk, height, n, 128);
        build_st();
        init();
        for (int i = 1; i <= n; i++) {
            v.push_back(sa[i]);
        }
        sort(v.begin(),v.end());
        for (int i=1;i<=n;i++){
            insert(1, n, root[i - 1], root[i], getid(sa[i]));
        }
        while (q--) {
            int l, r, k;
            scanf("%d%d%d", &l, &r, &k);
            int ll, rr, len = r - l + 1;
            int left = 1, right = rk[l];
            int ans = rk[l];
            while (left <= right) {
                int mid = (left + right) >> 1;
                if (lcp(sa[mid], l) >= len) {
                    right = mid - 1;
                    ans = mid;
                } else {
                    left = mid + 1;
                }
            }
            ll = ans;
            ans = rk[l];
            left = rk[l];
            right = n;
            while (left <= right) {
                int mid = (left + right) >> 1;
                if (lcp(sa[mid], l) >= len) {
                    left = mid + 1;
                    ans = mid;
                } else {
                    right = mid - 1;
                }
            }
            rr=ans;
            if (rr-ll+1<k) printf("-1\n");else{
                printf("%d\n",v[query(1,n,root[ll-1],root[rr],k)-1]);
            }
        }
    }
}

 不难看出对于每次2操作,答案最大是n+1(因为每次更新是+10000000, 永远不会占用n+1,而且k是保证<=n的). 如果某个数字被进行过1操作, 那么就代表这个数字可以用于2类操作的查询,把这个数字加到set里.对于找2类询问的答案,第一种是从a[r+1,n]里找>=k的最小值(主席树实现),第二种是从这个set里找>=k的最小值(对set进行二分查找),取两者间最小值即可.

#include <bits/stdc++.h>
using namespace std;
const int maxn=200100;
struct node
{
    int l,r,sum;
} hjt[maxn*40];
int cnt,root[maxn*20],n,m,book[maxn];
int a[maxn];
set<int>s;
set<int>::iterator it;
void init() {
    for (int i = 0; i <= n; i++) book[i] = 0;
    s.clear();
    root[0] = 0;
    cnt = 0;
    for (int i = 0; i < maxn * 20; i++) hjt[i].l = hjt[i].r = hjt[i].sum = 0;
}
void insert(int l,int r,int pre,int &now,int p)
{
    hjt[++cnt]=hjt[pre];
    now=cnt;
    hjt[now].sum++;
    if (l==r)
    {
        return;
    }
    int mid=(l+r)>>1;
    if (p<=mid)
    {
        insert(l,mid,hjt[pre].l,hjt[now].l,p);
    }
    else
    {
        insert(mid+1,r,hjt[pre].r,hjt[now].r,p);
    }
}
int query(int rt,int l,int r,int L,int R) {
    if (R < L) return -1;
    if (!rt) return -1;
    if (!hjt[rt].sum) return -1;
    if (l >= L && r <= R) {
        if (l == r)
            return l;
        else {
            int mid = (l + r) >> 1;
            int res = -1;
            if (L <= mid) res = query(hjt[rt].l, l, mid, L, R);
            if (R > mid && res == -1) res = query(hjt[rt].r, mid + 1, r, L, R);
            return res;
        }
    }
    int mid = (l + r) >> 1;
    int res = -1;
    if (L <= mid) res = query(hjt[rt].l, l, mid, L, R);
    if (R > mid && res == -1) res = query(hjt[rt].r, mid + 1, r, L, R);
    return res;
}

int main() {
    int _;
    scanf("%d", &_);
    while (_--) {
        scanf("%d%d", &n, &m);
        init();
        root[n + 1] = 0;
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for (int i = n; i >= 1; i--)
            insert(1, n, root[i + 1], root[i], a[i]);
        int lastans = 0;
        for (int i = 1; i <= m; i++) {
            int id;
            scanf("%d", &id);
            if (id == 1) {
                int t;
                scanf("%d", &t);
                int pos = t ^lastans;
                if (book[pos]) continue;
                book[pos] = 1;
                s.insert(a[pos]);
            } else {
                int t1, t2;
                scanf("%d%d", &t1, &t2);
                int R = (t1 ^lastans) + 1;
                int k = t2 ^lastans;
                int ans = n + 1;
                it = s.lower_bound(k);
                if (it != s.end()) ans = *it;
                if (R <= n) {
                    t1 = query(root[R], 1, n, k, n);
                    if (t1 != -1) ans = min(ans, t1);
                }
                printf("%d\n", ans);
                lastans = ans;
            }
        }
    }
    return 0;
}

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
ll a,b;
int main()
{
    int T;

    cin>>T;
    while(T--)
    {
        cin>>a>>b;
        ll ans=(a&b);
        if(ans==0){
            ans=1;
        }
        printf("%lld\n",ans);
    }
    return 0

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e4+10;
ll n,m,q,Q[maxn],ans[maxn],kk;
typedef pair<ll,int> PII;
vector<PII>G[maxn];
multiset<PII>s;
multiset<PII>::iterator it,it1;
int main() {
    int _;
    scanf("%d", &_);
    while (_--) {
        s.clear();
        kk=0;
        scanf("%lld%lld%lld", &n, &m, &q);
        for (int i = 1; i <= n; i++) G[i].clear();
        for (int i = 1, u, v, w; i <= m; i++) {
            scanf("%d%d%d",&u,&v,&w);
            G[u].push_back(make_pair(w, v));
            s.insert(make_pair(w, v));
        }
        for (int i = 1; i <= n; i++) {
            sort(G[i].begin(), G[i].end());
        }
        for (int i = 1; i <= q; i++) {
            scanf("%lld", &Q[i]);
            kk = max(kk, Q[i]);
        }
        for (int i = 1; i <= kk; i++) {
            it = s.begin();
            it1 = s.end();
            it1--;
            ans[i] = it->first;
            int sz1 = s.size();
            int sz = G[it->second].size();
            for (int j = 0; j < sz; j++) {
                if (s.size() >= kk-i+1 && it->first + G[it->second][j].first >= it1->first) break;
                s.insert(make_pair(it->first + G[it->second][j].first, G[it->second][j].second));
            }
            s.erase(it);
            while (s.size()>=kk-i+1) it=s.end(),--it,s.erase(it);
        }
        for (int i = 1; i <= q; i++) printf("%lld\n", ans[Q[i]]);
    }
    return 0;
}

#include <bits/stdc++.h>

using namespace std;
const int maxn=1e5+10;
int n,m;
deque<int>q;
int a[maxn],ans[maxn],vis[maxn],x,k;
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    for (int i = 1; i <= m; i++) {
        scanf("%d", &x);
        q.push_front(x);
    }
    while (!q.empty()) {
        int x = q.front();
        if (vis[x] == 0) ans[k++] = x;
        q.pop_front();
        vis[x] = 1;
    }
    for (int i = 1; i <= n; i++) {
        if (vis[i] == 0) {
            ans[k++] = i;
        }
    }
    for (int i = 0; i < k; i++) {
        printf("%d ", ans[i]);
    }
    //printf("\n");
}

 

posted @ 2019-08-23 21:15  Snow_in_winer  阅读(592)  评论(0编辑  收藏  举报