2018CCPC网络赛2018年8月25日

版权声明:https://github.com/godspeedcurry 欢迎加好友哦 https://blog.csdn.net/qq_38677814/article/details/82056327

吐槽一下网管中心,爬山去了没人看守?当这个比赛是啥?虽说是周末也不该这样子吧
本次比赛主要负责看题,人有点难过也做不出题系列(
按照签到顺序写题解
第一道费马大定理裸题 n>2无解
思路:n这么大暴算肯定不行呀,只有构造了~
构造思路队友想的很巧妙

#include <bits/stdc++.h>
using namespace std;
int main(){
    int t;
    cin>>t;
    while(t--){
        int n,a;
        scanf("%d %d",&n,&a);
        if(n==0){
            printf("-1 -1\n");
        }
        else if(n==1){
            printf("%d %d\n",1,a+1 );
        }
        else if(n==2){
            if(a&1){
                printf("%d %d\n",(a*a-1)>>1,(a*a+1)>>1 );//奇数的构造
            }
            else if((a&(a-1))==0){//2的次方 可以通过 4,3,5构造
                printf("%d %d\n",a/4*3,a/4*5);
            }
            else{//其它偶数情况 比如 6  我们把它变成36 8 10 -> 3 4 5这些是等价的
                int u;
                for(int i=1;;i++){
                    if((a>>i)&1){
                        u=i;
                        break;
                    }
                }
                int temp=a>>u;
                printf("%d %d\n",((temp*temp-1)>>1)<<u, ((temp*temp+1)>>1)<<u);
            }
        }
        else{
            printf("-1 -1\n");
        }
    }
    return 0;
}

1009
题意:给你一棵树,每个边有边权,统计所有排列下(全排列)的路径和
思路:N很大 不可能枚举全排列,转化成计算贡献
什么时候会通过1条边,左边到右边,右边到左边
假设左边的大小为L,右边为R 显然L+R=n
N!种全排列中经过该边的次数有多少呢
L*R个点集对
2*L*R个排列方式
对于每一点对,其他点对排列方式(N-2)!
捆绑插空 空位N-1个
sum= ∑cost_of_edge*(2*L*R)*(N-1)!
阶乘可以预处理
左右两边的大小可以通过一次dfs得到

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define MOD (int)(1e9+7)
#define mp(a,b) make_pair(a,b)
inline void rd(int &x){
    scanf("%d",&x);
}
struct edge{
    int x,y,l;
}e[100200];
int siz[102000];
int vis[102000];
vector<pair<int,int> > G[102000];
void dfs(int x){
    siz[x]=1;
    for(int i=0;i<G[x].size();i++){
        int to=G[x][i].first;
        if(!vis[to]){
            vis[to]=1;
            dfs(to);
            vis[to]=0;
            siz[x]+=siz[to];
        }
    }
}
ll fac[102000];
void init(){
    fac[0]=1;
    for(int i=1;i<=101000;i++){
        fac[i]=(fac[i-1]*i)%MOD;
    }
}
int main(int argc, char const *argv[])
{
    init();
    int n,x,y,l;
    while(~scanf("%d",&n)){
        memset(siz,0,sizeof(siz));
        for(int i=1;i<=n;i++){
            G[i].clear();
        }
        for(int i=1;i<n;i++){
            rd(x);rd(y);rd(l);
            e[i].x=x;
            e[i].y=y;
            e[i].l=l;
            G[x].push_back(mp(y,l));
            G[y].push_back(mp(x,l));
        }
        vis[1]=1;
        dfs(1);
        ll ans=0;
        for(int i=1;i<n;i++){
            int Min=min(siz[e[i].x],siz[e[i].y]);
            int Ltree=Min;
            int Rtree=n-Min;
            ans+=2ll*e[i].l*Ltree*Rtree%MOD*fac[n-1]%MOD;
            ans%=MOD;
        }
        printf("%lld\n",ans );
    }
    return 0;
}

1010
dp+数据结构维护(树状数组或者线段树)

#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x&(-x))
struct node{
    int x,y,v;
}p[100200];
int dp[100200],num[100200],a[100200],t;
bool cmp(node a,node b){
    return a.x!=b.x?a.x<b.x:a.y<b.y;
}
void init(){
    memset(dp,0,sizeof dp);
    memset(num,0,sizeof num);
}
void update(int x,int val){
    for(int i=x;i<=t;i+=lowbit(i)){
        num[i]=max(num[i],val);
    }
}
int query(int x){
    int res=0;
    for(int i=x;i;i-=lowbit(i)){
        res=max(res,num[i]);
    }
    return res;
}
int main(){
    int T;scanf("%d",&T);
    int n;
    while(T--){
        init();
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].v);
        }
        for(int i=1;i<=n;i++) a[i]=p[i].y;
        sort(a+1,a+1+n);
        t=unique(a+1,a+1+n)-a-1;//离散化 去重
        for(int i=1;i<=n;i++){
            p[i].y=lower_bound(a+1,a+1+t,p[i].y)-a;//重新赋值
        }
        sort(p+1,p+1+n,cmp);
        int ans=0;
        int now=1;
        for(int i=1;i<=n;i++){
            dp[i]=p[i].v;
        }
        //树状数组维护了区间最大值
        for(int i=1;i<=n;i++){
            while(now<i&&p[now].x<p[i].x){
                update(p[now].y,dp[now]);//用dp[now]更新
                ++now;
            }
            dp[i]=p[i].v+query(p[i].y-1);
            ans=max(ans,dp[i]);
        }
        printf("%d\n",ans );
    }
    return 0;
}

1003
费马小定理:
a^(p-1)≡1(mod p)p为质数
∴(a+b)^p=(a+b)^(p-1)*(a+b)=a+b(mod p)
a^p+b^p=a*a^(p-1)+b*b^(p-1)(mod p)=a+b(mod p)
还有一个限制条件:
这里写图片描述
看的时候一脸懵逼,这是什么鬼
手算找了几个小的好像是对的?
引入定义-原根
这里写图片描述

#include <bits/stdc++.h>
using namespace std;
int main(){
    int T;cin>>T;
    while(T--){
        int p;cin>>p;
        for(int i=1;i<=p;i++){
            for(int j=1;j<=p;j++){
                printf("%d%c",((i-1)%p+(j-1)%p)%p,j==p?'\n':' ');
            }
        }
        for(int i=1;i<=p;i++){
            for(int j=1;j<=p;j++){
                printf("%d%c",((i-1)%p*(j-1)%p)%p,j==p?'\n':' ');
            }
        }
    }

    return 0;
}

1001
优先队列+贪心
有弹性的优先队列,即可以反悔
每次取出价格比当前城市低的,然后卖掉,得到差价
可能后面的城市还有出价更高的,那我们需要把之前的退掉,然后再次得到差价
可以用map记录一下卖出的东西

#include <bits/stdc++.h>
using namespace std;
#define ll long long
map<int,int> sell;
priority_queue<ll,vector<ll>,greater<ll> > PQ;
ll a[100202];
void init(){
    while(!PQ.empty()){
        PQ.pop();
    }
    sell.clear();   
}   
int main(){
    int T;cin>>T;
    while(T--){
        int n;cin>>n;
        for(int i=1;i<=n;i++) scanf("%I64d",a+i);
        ll ans=0;
        int cnt=0;
        init();
        //第一个城市会把物品放进优先队列
        //以后的城市会取出最小的物品,然后如果当地价格高于他则卖掉
        //买卖次数+1
        //如果那个物品曾经卖出过 不卖,然后修改次数
        for(int i=1;i<=n;i++){
            if(!PQ.empty()&&PQ.top()<a[i]){
                ll Min=PQ.top();PQ.pop();
                ans+=a[i]-Min;
                cnt++;
                auto It=sell.find(Min);
                if(It!=sell.end()){
                    cnt--;
                    if(--sell[Min]==0){
                        sell.erase(It);
                    }
                }
                sell[a[i]]++;
                PQ.push(a[i]);
            }
            PQ.push(a[i]);
        }
        printf("%I64d %d\n",ans,cnt*2);
    }
    return 0;
}

1007
循环节很容易想到,难点在于一些细节的处理

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+100;
ll n,m,s,k;
ll a[maxn];
ll pre[maxn<<1];
ll seg[maxn<<2];
inline ll ls(ll x){
    return x<<1;
}
inline ll rs(ll x){
    return x<<1|1;
}
inline void push_up(ll rt){
    seg[rt]=min(seg[ls(rt)],seg[rs(rt)]);
}
void build(ll l,ll r,ll rt){
    if(l==r){
        seg[rt]=pre[l];
        return;
    }
    ll mid=(l+r)>>1;
    build(l,mid,ls(rt));
    build(mid+1,r,rs(rt));
    push_up(rt);
}
ll query(ll L,ll R,ll l,ll r,ll rt){
    ll res=1ll<<60;
    if(L<=l&&r<=R){
        return seg[rt];
    }
    ll mid=(l+r)>>1;
    if(L<=mid) res=min(res,query(L,R,l,mid,ls(rt)));
    if(R>mid) res=min(res,query(L,R,mid+1,r,rs(rt)));
    push_up(rt);
    return res;
}
int main(){
    int T;cin>>T;
    for(int c=1;c<=T;c++){
        scanf("%I64d%I64d%I64d%I64d",&n,&s,&m,&k);
        memset(pre,0,sizeof(pre));
        for(ll i=0;i<n;i++){
            scanf("%I64d",a+i);
        }
        ll ans=0;
        ll num=__gcd(n,k);
        ll len=n/num;
        for(int i=1;i<=num;i++){
            int index=i-1;
            for(int j=1;j<=len;j++){
                pre[j]=pre[j+len]=a[index];
                index=(index+k)%n;
            }
            for(int j=1;j<=len*2;++j){
                pre[j]+=pre[j-1];
            }
            build(1,len<<1,1);
            ll ans1=0;
            ll res=0;
            for(int j=len+1;j<=len*2;j++){
                res=max(res,pre[j]-query(j-(m%len),j,1,len<<1,1));
            }
            if(m<len){
                ans=max(res,ans);
                continue;
            }
            if(m%len)ans1+=res;
            if(pre[len]>0){
                ans1+=(m)/len*pre[len];
            }

            ll ans2=0;
            for(int j=len+1;j<=len*2;j++){
                ans2=max(ans2,pre[j]-query(j-len,j,1,len<<1,1));
            }
            if(pre[len]>0) ans2+=(m-len)/len*pre[len];//牺牲一个循环节去得到上面的那个答案
            ans=max(ans,max(ans1,ans2));
        }
        printf("Case #%d: %I64d\n",c,max(0ll,s-ans) );
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38677814/article/details/82056327
今日推荐