CCPC-Wannafly Winter Camp Day5 (Div2, onsite)

目录

 

A.Cactus Draw

C.Division

D.Doppelblock

F.Kropki

I.Sorting

J.Special Judge


A.Cactus Draw

根据深度建点,队友代码

#include<bits/stdc++.h>
using namespace std;

int n,m;

vector<int>t[1005];
pair<int,int> ans[1005];
int h[1005];

void dfs(int u,int fa,int dep)
{
    ans[u]=make_pair(dep,h[dep]++);
    for(int i=0;i<t[u].size();i++)
    {
        int v=t[u][i];
        if(v==fa)continue;
        dfs(v,u,dep+1);
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    int u,v;
    fill(h+1,h+1005,1);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        t[u].push_back(v);
        t[v].push_back(u);
    }
    dfs(1,0,1);
    for(int i=1;i<=n;i++)
        printf("%d %d\n",ans[i].first,ans[i].second);
    return 0;
}

C.Division

从大到小贪心操作就行了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=2e5+5;
ll a[N];
int main()
{
    ll n,k,x;
    scanf("%lld%lld",&n,&k);
    priority_queue<ll>q;
    for(ll i=1;i<=n;i++){
        scanf("%lld",&x);
        q.push(x);
    }
    ll ans=0,cnt=0;
    while(1){
        ll t=q.top();q.pop();
        if(t==0) break;
        q.push(t/2);
        cnt++;
        if(cnt>=k) break;
    }
    while(!q.empty()){
        ans+=q.top();q.pop();
    }
    printf("%lld\n",ans);
    return 0;
}

D.Doppelblock

暴力搜索,加一些减枝。如果两个X内的数之和不是要求的,剪掉;如果还没放过X,但剩下的数字没法达到要求了,剪掉。

还可以预处理X的位置,没有写。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=10;
int row[N][N],col[N][N];
int r[N],c[N],tr[N],tc[N];
int t,n,tot;
char pr[N][N];
bool dfs(int x,int y){
    if(x>n) return true;
    for(int i=1;i<=n-2;i++){
        if(row[x][i]) continue;
        if(col[y][i]) continue;
        if(row[x][0]==0){
            if(tr[x]+i+r[x]>tot) continue;
        }
        else if(row[x][0]==1){
            if(tr[x]+i>r[x]) continue;
        }
        if(col[y][0]==0){
            if(tc[y]+i+c[y]>tot) continue;
        }
        else if(col[y][0]==1){
            if(tc[y]+i>c[y]) continue;
        }
        pr[x][y]='0'+i;
        row[x][i]=true;col[y][i]=true;
        tr[x]+=i;tc[y]+=i;
        if(y==n){
            if(dfs(x+1,1)) return true;
        }
        else{
            if(dfs(x,y+1)) return true;
        }
        row[x][i]=false;col[y][i]=false;
        tr[x]-=i;tc[y]-=i;
    }
    if(row[x][0]==2) return false;
    if(col[y][0]==2) return false;
    if(row[x][0]==1&&tr[x]!=r[x]) return false;
    if(col[y][0]==1&&tc[y]!=c[y]) return false;
    pr[x][y]='X';
    row[x][0]++;col[y][0]++;
    int ttr=tr[x],ttc=tc[y];
    tr[x]=tc[y]=0;
    if(y==n){
        if(dfs(x+1,1)) return true;
    }
    else{
        if(dfs(x,y+1)) return true;
    }
    row[x][0]--;col[y][0]--;
    tr[x]=ttr;tc[y]=ttc;
    return false;
}
void init(){
    tot=(n-1)*(n-2)/2;
    for(int i=0;i<=n;i++){
        r[i]=c[i]=tr[i]=tc[i]=0;
        for(int j=0;j<=n;j++){
            row[i][j]=col[i][j]=0;
        }
    }
}
int main()
{

    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        init();
        for(int i=1;i<=n;i++) scanf("%d",&r[i]);
        for(int i=1;i<=n;i++) scanf("%d",&c[i]);
        dfs(1,1);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                printf("%c",pr[i][j]);
            }
            printf("\n");
        }
        printf("\n");
    }
    return 0;
}

F.Kropki

dp[i][s][k]表示第i位,状态为s,最后一位放k,然后按题意做即可。注意,第一维不能舍去。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=5e4+7;
char st[50];
int dp[50][N][50];
int num[N];
int sum[50][N];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<(1<<n);i++)
        num[i]=num[i&(i-1)]+1;
    scanf("%s",st+1);
    for(int i=1;i<=n;i++){
        dp[1][1<<(i-1)][i]=1;
        sum[1][1<<(i-1)]=1;
    }
    for(int i=2;i<=n;i++){
        for(int s=0;s<(1<<n);s++){
            if(num[s]!=i) continue;
            for(int k=1;k<=n;k++){
                if(s&(1<<(k-1))){
                    int ss=s-(1<<(k-1));
                    if(st[i-1]=='0'){
                        dp[i][s][k]=sum[i-1][ss];
                        if(k%2==0){
                            int tmp=k/2;
                            dp[i][s][k]=(dp[i][s][k]-dp[i-1][ss][tmp]+mod)%mod;
                        }
                        if(k*2<=n){
                            int tmp=k*2;
                            dp[i][s][k]=(dp[i][s][k]-dp[i-1][ss][tmp]+mod)%mod;
                        }
                    }
                    else{
                        dp[i][s][k]=0;
                        if(k%2==0){
                            int tmp=k/2;
                            dp[i][s][k]=(dp[i][s][k]+dp[i-1][ss][tmp])%mod;
                        }
                        if(k*2<=n){
                            int tmp=k*2;
                            dp[i][s][k]=(dp[i][s][k]+dp[i-1][ss][tmp])%mod;
                        }
                    }
                    sum[i][s]=(sum[i][s]+dp[i][s][k])%mod;
                }
            }
        }
    }
     printf("%d\n",sum[n][(1<<n)-1]);
}

I.Sorting

因为x是固定的,所以小于等于x的数字相对顺序不会改变,大于x的数字相对顺序也不会改变。把前者看成0,后者看成1,这样就构造成了一个01序列。然后把原先的数字分开按照0和1分开存储前缀和。

  • 对于修改操作,就是查询这段区间有多少个0和1,然后把左右边赋值成0或1.
  • 对于查询操作,查询前缀有多少个1来确定询问区间的1的所在位置,并用前缀和来计算答案,0也同理。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+7;
int n,q,x,tmp;
ll sum0[N],sum1[N];
int t0,t1;
int t[N<<2],lz[N<<2];
void bd(int rt,int l,int r){
    lz[rt]=-1;
    if(l==r){
        scanf("%d",&tmp);
        if(tmp<=x){
            t[rt]=0;t0++;
            sum0[t0]=tmp+sum0[t0-1];
        }
        else{
            t[rt]=1;t1++;
            sum1[t1]=tmp+sum1[t1-1];
        }
        return;
    }
    int m=l+r>>1;
    bd(rt<<1,l,m);
    bd(rt<<1|1,m+1,r);
    t[rt]=t[rt<<1]+t[rt<<1|1];
}
void pd(int rt,int l,int r){
    if(~lz[rt]){
        int m=l+r>>1;
        lz[rt<<1]=lz[rt<<1|1]=lz[rt];
        t[rt<<1]=lz[rt]*(m-l+1);
        t[rt<<1|1]=lz[rt]*(r-m);
        lz[rt]=-1;
    }
}
void upd(int rt,int l,int r,int L,int R,int val){
    if(L<=l&&r<=R){
        t[rt]=(r-l+1)*val;
        lz[rt]=val;
        return;
    }
    pd(rt,l,r);
    int m=l+r>>1;
    if(L<=m) upd(rt<<1,l,m,L,R,val);
    if(m<R) upd(rt<<1|1,m+1,r,L,R,val);
    t[rt]=t[rt<<1]+t[rt<<1|1];
}
int que(int rt,int l,int r,int L,int R){
    if(L<=l&&r<=R) return t[rt];
    pd(rt,l,r);
    int m=l+r>>1,res=0;
    if(L<=m) res+=que(rt<<1,l,m,L,R);
    if(m<R) res+=que(rt<<1|1,m+1,r,L,R);
    return res;
}
int main()
{
    scanf("%d%d%d",&n,&q,&x);
    bd(1,1,n);
    while(q--){
        int t,l,r;
        scanf("%d%d%d",&t,&l,&r);
        if(t==1){
            int nr=que(1,1,n,1,r),nl;
            if(l>1) nl=que(1,1,n,1,l-1);
            else nl=0;
            ll ans=sum1[nr]-sum1[nl];
            ans+=sum0[r-nr]-sum0[l-1-nl];
            printf("%lld\n",ans);
        }
        else if(t==2){
            int num=r-l+1-que(1,1,n,l,r);
            upd(1,1,n,l,l+num-1,0);
            upd(1,1,n,l+num,r,1);
        }
        else{
            int num=que(1,1,n,l,r);
            upd(1,1,n,l,l+num-1,1);
            upd(1,1,n,l+num,r,0);
        }
    }
    return 0;
}

J.Special Judge

板子加细节判断,队友代码

#include<bits/stdc++.h>
using namespace std;



#define mp make_pair
#define fi first
#define se second
#define pb push_back
typedef double db;
const db eps=1e-6;
const db pi=acos(-1);
int sign(db k){
    if (k>eps) return 1; else if (k<-eps) return -1; return 0;
}
int cmp(db k1,db k2){return sign(k1-k2);}
int inmid(db k1,db k2,db k3){return sign(k1-k3)*sign(k2-k3)<=0;}// k3 在 [k1,k2] 内

struct point{
    db x,y;
    point(){}
    point(int x,int y){this->x=(db)x;this->y=(db)y;}
    point operator + (const point &k1) const{return (point){k1.x+x,k1.y+y};}
    point operator - (const point &k1) const{return (point){x-k1.x,y-k1.y};}
    point operator * (db k1) const{return (point){x*k1,y*k1};}
    point operator / (db k1) const{return (point){x/k1,y/k1};}
    int operator == (const point &k1) const{return cmp(x,k1.x)==0&&cmp(y,k1.y)==0;}
    // 逆时针旋转
    point turn(db k1){return (point){x*cos(k1)-y*sin(k1),x*sin(k1)+y*cos(k1)};}
    point turn90(){return (point){-y,x};}
    bool operator < (const point k1) const{
        int a=cmp(x,k1.x);
        if (a==-1) return 1; else if (a==1) return 0; else return cmp(y,k1.y)==-1;
    }
    db abs(){return sqrt(x*x+y*y);}
    db abs2(){return x*x+y*y;}
    db dis(point k1){return ((*this)-k1).abs();}
    point unit(){db w=abs(); return (point){x/w,y/w};}
    void scan(){double k1,k2; scanf("%lf%lf",&k1,&k2); x=k1; y=k2;}
    void print(){printf("%.11lf %.11lf\n",x,y);}
    db getw(){return atan2(y,x);}
    point getdel(){if (sign(x)==-1||(sign(x)==0&&sign(y)==-1)) return (*this)*(-1); else return (*this);}
	int getP() const{return sign(y)==1||(sign(y)==0&&sign(x)==-1);}
};
int inmid(point k1,point k2,point k3){return inmid(k1.x,k2.x,k3.x)&&inmid(k1.y,k2.y,k3.y);}
db cross(point k1,point k2){return k1.x*k2.y-k1.y*k2.x;}
int intersect(db l1,db r1,db l2,db r2){
    if (l1>r1) swap(l1,r1); if (l2>r2) swap(l2,r2); return cmp(r1,l2)!=-1&&cmp(r2,l1)!=-1;
}

int checkSS(point k1,point k2,point k3,point k4){
    return intersect(k1.x,k2.x,k3.x,k4.x)&&intersect(k1.y,k2.y,k3.y,k4.y)&&
    sign(cross(k3-k1,k4-k1))*sign(cross(k3-k2,k4-k2))<=0&&
    sign(cross(k1-k3,k2-k3))*sign(cross(k1-k4,k2-k4))<=0;
}

int onS(point k1,point k2,point q){return inmid(k1,k2,q)&&sign(cross(k1-q,k2-k1))==0;}

map<int,point>mm;

struct node
{
    int u,v;
    int nxt;
}edge[2005];

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d",&edge[i].u,&edge[i].v);
    int x,y;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&x,&y);
        mm[i]=point(x,y);
    }
    int ans=0;
    for(int i=1;i<m;i++)
    {
        for(int j=i+1;j<=m;j++)
        {
            point p1=mm[edge[i].u],p2=mm[edge[i].v],p3=mm[edge[j].u],p4=mm[edge[j].v];
            int tp=checkSS(p1,p2,p3,p4);
            if(tp==0)continue;
            else if(((p1==p3||p1==p4)&&onS(p3,p4,p2))||((p2==p4||p2==p3)&&onS(p3,p4,p1))||((p3==p1||p3==p2)&&onS(p1,p2,p4))||((p4==p1||p4==p2)&&onS(p1,p2,p3)));
            else if(p1==p3||p1==p4||p2==p3||p2==p4)continue;
            ans++;
        }
    }
    printf("%d\n",ans);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值