首页 > 代码库 > 2016 CCPC 网络赛 B 高斯消元 C 树形dp(待补) G 状压dp+容斥(待补) H 计算几何

2016 CCPC 网络赛 B 高斯消元 C 树形dp(待补) G 状压dp+容斥(待补) H 计算几何

2016 CCPC 网络赛

A - A water problem 水题,但读题有个坑,输入数字长度很大。。

B - Zhu and 772002

题意:给出n个数(给出的每个数的质因子最大不超过2000),选出多个数相乘得b。问有多少种选法让b 为完全平方数。

tags:高斯消元,求异或方程组解的个数。   好题

每个数先素数分解开。  对于2000以内的每个素数p[i],这n个数有奇数个p[i]则系数为1,偶数个则系数为0,最后n个数的p[i]系数异或和都要为0才会使得最后的积为完全平方数。    所以,构建出系数矩阵,然后高斯消元,解出异或方程组的秩rank,自由变元的数量即为 x=n-rank,最后解的个数为2^x,但要注意减去全部为0的一种情况。

技术分享
#include<bits/stdc++.h>using namespace std;#pragma comment(linker, "/STACK:102400000,102400000")#define rep(i,a,b) for (int i=a;i<=b;i++)#define per(i,b,a) for (int i=b;i>=a;i--)#define mes(a,b)  memset(a,b,sizeof(a))#define INF 0x3f3f3f3ftypedef long long ll;const int N = 2000, M=310, mod=1000000007;int pri[N], cnt;   bool mark[N+1];void sieve_prime(){    rep(i,2,N) {        if(mark[i]==0) pri[++cnt]=i;        for(int j=i*i; j<=N; j+=i) mark[j]=1;    }}int fpow(ll a,int b){ll ans=1; for(;b;b>>=1,a=a*a%mod) if(b&1) ans=ans*a%mod; return (int)ans;}  int n, mat[M][M];ll a[N];int gauss_rank(int c[][M])    //高斯消元求异或方程组的秩 {    int i=1, j=1;    while(i<=cnt && j<=n) {        int r=0;        rep(k,i,cnt) if(mat[k][j]) { r=k; break; }        if(r)         {              swap(mat[r], mat[i]);            rep(k,i+1,cnt) if(mat[k][j]) {                rep(h,i,n) mat[k][h]^=mat[i][h];            }            i++;        }        j++;    }    return i-1;}int solve(){    rep(j,1,n) {        ll tmp=a[j];               rep(i,1,cnt) {    //构建系数矩阵             while(tmp%pri[i]==0) {                 tmp/=pri[i], mat[i][j]^=1;            }        }    }    int x=n-gauss_rank(mat);     //自由变元数量     return (fpow(2,x)-1+mod)%mod;}int main(){    sieve_prime();    int T;   scanf("%d", &T);    rep(cas,1,T) {        mes(mat, 0);        scanf("%d", &n);        rep(i,1,n) scanf("%lld", &a[i]);        printf("Case #%d:\n%d\n", cas, solve());    }    return 0;}
View Code

C - Magic boy Bi Luo with his excited tree

题意:给出一棵树,在每个点有a[i]的财宝,但每条边有v[i]的花费,问从每个结点出发可得到的最大钱财数ans[i]。

tags:树形dp,好伤脑细胞的题。。码了好几发,莫名其妙的错,  待补

把每个结点分为往儿子不回来v1、往儿子回来v2、往父亲不回来fv1、往父亲回来fv2。第一次dfs维护出v1和v2,第二次dfs维护出fv1和fv2,最后答案就是max(v1+fv2, v2+fv1)。 

D - Danganronpa

题意:n种礼物,每种有a[i]个。无穷多个学生的桌子排成一行,限制:1、每张桌子里要有一个神秘礼物和一个普通礼物;2、相邻的桌子里的普通礼物要不同;3、礼物要放在相邻的桌子里。    问最多有多少个学生拿到礼物。

tags:思维题,稍微理一下 maxn和sum/2 就好。

技术分享
// D#include<bits/stdc++.h>using namespace std;#pragma comment(linker, "/STACK:102400000,102400000")#define rep(i,a,b) for (int i=a;i<=b;i++)#define per(i,b,a) for (int i=b;i>=a;i--)#define mes(a,b)  memset(a,b,sizeof(a))#define INF 0x3f3f3f3ftypedef long long ll;const int N = 200005;int T, n, ai;int main(){    scanf("%d", &T);    rep(cas,1,T) {        scanf("%d", &n);        ll sum=0;        int mx=0;        rep(i,1,n) {            scanf("%d", &ai);            sum+=ai;            mx=max(mx, ai);        }        ll ans;        if(mx>sum/2) ans=min(((sum-mx)*2)+1, sum/2);        else ans=sum/2;        printf("Case #%d: %lld\n", cas, ans);    }     return 0;}
View Code

G - Mountain

题意: n*m的网格,每个网格有一个高度。定义周围网格高度都比其大的网格为山谷。给出了网格中的山谷位置,网格高度可以是1~n*m,但网格高度互不相同,求有多少种方案。

tags:bzoj 2669: [cqoi2012]局部极小值  原题   

没搞懂,待补

技术分享
// CCPC  Gconst int maxn=1<<9, mod=772002;char c[26][26];int dp[26][maxn];    // dp[i][s]表示‘X‘的状态为s时,已经填数字填到了i的方案数int a[8]={-1,-1,-1,0,1,1,1,0};int b[8]={-1,0,1,1,1,0,-1,-1};int n,m;int id[26][26];    // id[i][j]表示第 i行 j列是第几个‘X‘,或者是 0则不是‘X‘ int cnt[maxn];int nn[maxn];int cal(int p){    //走过了 p个‘X‘     int w=1<<p;    for(int i=0;i<w;i++){        cnt[i]=0;        for(int j=0;j<n;j++){            for(int f=0;f<m;f++){                if(c[j][f]==.){    //                     int flag=0;                    for(int u=0;u<8;u++){                        int x=j+a[u];                        int y=f+b[u];                        if(x>=0&&x<n&&y>=0&&y<m){                            if(c[x][y]==X&&(i&(1<<id[x][y]))==0){                                flag=1;    //不产生贡献                                 break;                            }                        }                    }                    cnt[i]+=flag^1;                }            }        }    }    dp[0][0]=1;    for(int i=1;i<=n*m;i++) {        for(int j=0;j<w;j++) {            dp[i][j]=((LL)dp[i-1][j]*(cnt[j]-(i-1-nn[j])))%mod;        //             for(int q=0;q<p;q++) {                if(j&(1<<q)) {                    dp[i][j]+=dp[i-1][j^(1<<q)];    //                    dp[i][j]%=mod;                }            }        }    }    return dp[n*m][w-1];}int dfs(int x,int y,int p){    // 从(x,y)开始,有 t个‘.‘变为了‘X‘,走过了p个‘X‘    if(x==n){        if(t%2==0){            return cal(p);        }        else return (mod-cal(p))%mod;    }    if(y==m) return dfs(x+1,0,p);    //换行    if(c[x][y]==X){        id[x][y]=p;        return dfs(x,y+1,p+1); //遍历过一个‘X‘,p加一     }    int flag=0;    for(int i=0;i<8;i++){        int x1=x+a[i];        int y1=y+b[i];        if(x1>=0&&x1<n&&y1>=0&&y1<m&&c[x1][y1]==X){            flag=1;        }    }    int ans=dfs(x,y+1,p);    if(flag==0){        id[x][y]=p;        c[x][y]=X;    //把‘.‘变为‘X‘        ans+=dfs(x,y+1,p+1);    // +=        ans%=mod;        c[x][y]=.;    //再变回         id[x][y]=0;    }    return ans;}int main(){    int N=0;    for(int i=1;i<maxn;i++) nn[i]=nn[i&(i-1)]+1;    while (scanf("%d%d",&n,&m)!=EOF) {        for(int i=0;i<n;i++) scanf("%s",c[i]);        int flag=0;        for(int i=0;i<n;i++){            for(int j=0;j<m;j++){                if(c[i][j]==X){                    for(int f=0;f<8;f++){                        int x=i+a[f];                        int y=j+b[f];                        if(x>=0&&x<n&&y>=0&&y<m){                            if(c[x][y]==X){                                flag=1;                            }                        }                    }                }            }        }        printf("Case #%d: ",++N);        if(flag) printf("0\n");        else{            printf("%d\n",dfs(0,0,0));        }    }}
View Code

H - Special Tetrahedron

题意:三维空间给出n 个点。定义特殊四面体:1、至少有4条相同长度的边;2、如果恰好有4条相同长度的边,另两条边要不相邻。 问有多少个特殊四面体。

tags:看了大神题解码的,转送门

思路:可以看成是求空间四边形,暴力枚举对角线。 对于每一条对角线,再枚举,把到两端点距离相等的点加到集合里。然后再枚举,看集合里任意两个点是否与两个端点共面。    最后去重,正四面体算了6次,两条边不等的算了2次。  时间复杂度O(n^4),但实际上,两个点与对角线两端点共面的情况只能在对角线中垂线上,不可能每次都有很多点在中垂线上,所以均摊下来时间复杂度并不高。

技术分享
#include<bits/stdc++.h>using namespace std;#pragma comment(linker, "/STACK:102400000,102400000")#define rep(i,a,b) for (int i=a;i<=b;i++)#define per(i,b,a) for (int i=b;i>=a;i--)#define mes(a,b)  memset(a,b,sizeof(a))#define INF 0x3f3f3f3ftypedef long long ll;const int N = 210;struct Point {    double x, y, z;    Point operator - (const Point &b) const {        return Point{b.x-x, b.y-y, b.z-z};    }}p[N];double dis(Point a, Point b) {    return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) + (a.z-b.z)*(a.z-b.z));}Point xmul(Point a, Point b) {    //叉积     return Point{a.y*b.z-b.y*a.z, a.z*b.x-b.z*a.x, a.x*b.y-b.x*a.y};}double dmul(Point a, Point b) {    //返回 0则两向量垂直     return a.x*b.x+a.y*b.y+a.z*b.z;}bool isgm(Point a, Point b, Point c, Point d) {    //返回 0则四点花线     if(dmul(xmul(a-b,a-c), a-d)) return false;    return true;}int n; vector<Point > ve;int solve(){    int ans1=0, ans2=0;    rep(ca,1,n) rep(cb,ca+1,n) if(ca!=cb) {    //枚举对角线         ve.clear();        rep(i,1,n) if(i!=ca && i!=cb) {            if(dis(p[i],p[ca])==dis(p[i],p[cb])) ve.push_back(p[i]);        }        int sz=ve.size();         rep(i,0,sz-1) {            double dis1=dis(ve[i],p[ca]);             rep(j,i+1,sz-1) if(dis(ve[j],p[ca])==dis1) {                if(isgm(p[ca],p[cb],ve[i],ve[j]))  continue;                if(dis(ve[i],ve[j])==dis1 && dis(p[ca],p[cb])==dis1) ans2++;                else ans1++;            }        }    }     ans1/=2, ans1=ans1+ans2/6;    return ans1;}int main(){    int T;  scanf("%d", &T);    rep(cas,1,T) {        scanf("%d", &n);        rep(i,1,n) scanf("%lf %lf %lf", &p[i].x, &p[i].y, &p[i].z);        printf("Case #%d: %d\n", cas, solve());    }    return 0;}
View Code

K - Lweb and String

题意:一个字符串,它的字符集合里,求它能够形成的最长递增子序列长度。

tags: SB题     被坑了,看懂题意,感觉题目反常就多看几遍 ==

技术分享
#include<bits/stdc++.h>using namespace std;#pragma comment(linker, "/STACK:102400000,102400000")#define rep(i,a,b) for (int i=a;i<=b;i++)#define per(i,b,a) for (int i=b;i>=a;i--)#define mes(a,b)  memset(a,b,sizeof(a))#define INF 0x3f3f3f3ftypedef long long ll;const int N = 200005;int vis[200];string s;int main(){    int T;    scanf("%d", &T);    rep(cas,1,T) {        cin>>s;        int len=s.size();        mes(vis,0);        rep(i,0,len-1) vis[s[i]]=1;        int ans=0;        rep(i,0,199) if(vis[i]) ans++;        printf("Case #%d: %d\n", cas, ans);    }    return 0;}
View Code

2016 CCPC 网络赛 B 高斯消元 C 树形dp(待补) G 状压dp+容斥(待补) H 计算几何