ccpc網絡賽

1011:水題。c++

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;
const ll MOD=1e9+7;
const double EPS=1e-13;

char s[maxn];
int n;
int cnt[1200];

int main()
{
    //freopen("in.txt","r",stdin);
    int T;cin>>T;int casen=1;
    while(T--){
        printf("Case #%d: ",casen++);
        MS0(cnt);
        scanf("%s",s+1);
        n=strlen(s+1);
        REP(i,1,n) cnt[s[i]]=1;
        int res=0;
        REP(i,0,1100) res+=cnt[i];
        printf("%d\n",res);
    }
    return 0;
}
View Code

1001:水題。數組

吐槽:在我寫這道題以前,隊友貢獻了4次罰時。。。ide

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=10001000;
const int INF=1e9+10;
const ll MOD=1e9+7;
const double EPS=1e-13;

char s[maxn],t[maxn];
int n;

int lcm(int a,int b)
{
    return a/__gcd(a,b)*b;
}

int main()
{
    //freopen("in.txt","r",stdin);
    int casen=1;
    while(~scanf("%s",t)){
        printf("Case #%d: ",casen++);
        n=strlen(t);
        REP(i,0,n-1) s[i]=t[n-1-i];
        int x=lcm(73,137);
        int y=0;
        for(int i=n-1;i>=0;i--) y=(y*10+s[i]-'0')%x;
        puts(y?"NO":"YES");
    }
    return 0;
}
View Code

1004:水題,直接排序以後模擬。spa

吐槽:比賽的時候好多隊伍用sum/2水過的。。。debug

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;
const ll MOD=1e9+7;
const double EPS=1e-13;

int n;
int a[maxn];
int b[maxn],bn;

int main()
{
    //freopen("in.txt","r",stdin);
    int T;cin>>T;int casen=1;
    while(T--){
        printf("Case #%d: ",casen++);
        scanf("%d",&n);
        int sum=0;
        REP(i,1,n) scanf("%d",&a[i]),sum+=a[i];
        if(n==1){
            if(a[1]>=2) puts("1");
            else puts("0");
            continue;
        }
        sort(a+1,a+n+1);
        bn=0;
        int st=1;
        while(bn<sum/2&&st<n){
            REP(i,st,n){
                if(bn==sum/2||st==n) break;
                if(a[i]>0){
                    b[++bn]=a[i],a[i]--;
                    if(a[i]==0) st=i+1;
                }
            }
        }
        if(bn==sum/2) printf("%d\n",bn);
        else{
            int res=bn;
            REP(i,1,bn){
                if(res==sum/2) break;
                int tmpA=0,tmpB=0;
                if(i>=2&&b[i-1]!=n) tmpA=1;
                if(i<=bn&&b[i+1]!=n) tmpB=1;
                if(tmpA&&tmpB) res++;
            }
            printf("%d\n",res);
        }
    }
    return 0;
}
/**
5
2
3 2
1
10
3
1 2 3
3
2 2 10
2
1 1
*/
View Code

1002:水題。3d

x[i]爲每一個數取或不取,而後根據平方數質因子都爲偶數個,列%2的方程而後高斯消元,答案顯然爲非零解的個數,因爲x[i]取值只能爲0或1,因此答案爲2^自由變元-1。code

  1,沒有一眼看出是列方程求解的個數,靠隊友提醒纔想出來。blog

  2,提交的時候模數寫成了722002,貢獻了一次罰時。排序

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;
const ll MOD= 1000000007LL;
const double EPS=1e-13;

ll prime[510];int pn;
int n;
ll b[maxn];

///--
const int MAXN=510;
int a[MAXN][MAXN];//增廣矩陣
int x[MAXN];//解集
bool free_x[MAXN];//標記是不是不肯定的變元

ll qpow(ll n,ll k,ll p)
{
    ll res=1;
    while(k){
        if(k&1) res=(res*n)%p;
        n=(n*n)%p;
        k>>=1;
    }
    return res;
}

inline int gcd(int a,int b)
{
    int t;
    while(b!=0)
    {
        t=b;
        b=a%b;
        a=t;
    }
    return a;
}
inline int lcm(int a,int b)
{
    return a/gcd(a,b)*b;//先除後乘防溢出
}

/// 高斯消元法解方程組(Gauss-Jordan elimination).(-2表示有浮點數解,但無整數解,
///-1表示無解,0表示惟一解,大於0表示無窮解,並返回自由變元的個數)
///有equ個方程,var個變元。增廣矩陣行數爲equ,分別爲0到equ-1,列數爲var+1,分別爲0到var.
int Gauss(int equ,int var)
{
    int i,j,k;
    int max_r;// 當前這列絕對值最大的行.
    int col;//當前處理的列
    int ta,tb;
    int LCM;
    int temp;
    int free_x_num;
    int free_index;

    for(int i=0;i<=var;i++)
    {
        x[i]=0;
        free_x[i]=true;
    }

    //轉換爲階梯陣.
    col=0; // 當前處理的列
    for(k = 0;k < equ && col < var;k++,col++)
    {// 枚舉當前處理的行.
// 找到該col列元素絕對值最大的那行與第k行交換.(爲了在除法時減少偏差)
        max_r=k;
        for(i=k+1;i<equ;i++)
        {
            if(abs(a[i][col])>abs(a[max_r][col])) max_r=i;
        }
        if(max_r!=k)
        {// 與第k行交換.
            for(j=k;j<var+1;j++) swap(a[k][j],a[max_r][j]);
        }
        if(a[k][col]==0)
        {// 說明該col列第k行如下全是0了,則處理當前行的下一列.
            k--;
            continue;
        }
        for(i=k+1;i<equ;i++)
        {// 枚舉要刪去的行.
            if(a[i][col]!=0)
            {
                LCM = lcm(abs(a[i][col]),abs(a[k][col]));
                ta = LCM/abs(a[i][col]);
                tb = LCM/abs(a[k][col]);
                if(a[i][col]*a[k][col]<0)tb=-tb;//異號的狀況是相加
                for(j=col;j<var+1;j++)
                {
                    a[i][j] = ((a[i][j]*ta-a[k][j]*tb)%2+2)%2;
                }
            }
        }
    }

    // 1. 無解的狀況: 化簡的增廣陣中存在(0, 0, ..., a)這樣的行(a != 0).
    for (i = k; i < equ; i++)
    { // 對於無窮解來講,若是要判斷哪些是自由變元,那麼初等行變換中的交換就會影響,則要記錄交換.
        if ( a[i][col]  != 0) return -1;
    }
    // 2. 無窮解的狀況: 在var * (var + 1)的增廣陣中出現(0, 0, ..., 0)這樣的行,即說明沒有造成嚴格的上三角陣.
    // 且出現的行數即爲自由變元的個數.
    if (k < var)
    {
        // 首先,自由變元有var - k個,即不肯定的變元至少有var - k個.
        for (i = k - 1; i >= 0; i--)
        {
            free_x_num = 0; // 用於判斷該行中的不肯定的變元的個數,若是超過1個,則沒法求解,它們仍然爲不肯定的變元.
            for (j = 0; j < var; j++)
            {
                if (a[i][j] != 0 && free_x[j]) free_x_num++, free_index = j;
            }
            if (free_x_num > 1) continue;
            temp = a[i][var];
            for (j = 0; j < var; j++)
            {
                if (a[i][j] != 0 && j != free_index) temp -= a[i][j] * x[j]%2;
                temp=(temp%2+2)%2;
            }
            x[free_index] = (temp / a[i][free_index])%2; // 求出該變元.
            free_x[free_index] = 0; // 該變元是肯定的.
        }
        return var - k; // 自由變元有var - k個.
    }
    for (i = var - 1; i >= 0; i--)
    {
        temp = a[i][var];
        for (j = i + 1; j < var; j++)
        {
            if (a[i][j] != 0) temp -= a[i][j] * x[j];
            temp=(temp%2+2)%2;
        }
        while (temp % a[i][i] != 0) temp+=2;
        x[i] =( temp / a[i][i])%2 ;
    }
    return 0;
}
///--

void solve()
{
    MS0(a);
    REP(j,0,n-1){
        ll x=b[j];
        REP(i,0,pn-1){
            ll t=prime[i];
            int k=0;
            while(x%t==0) x/=t,k^=1;
            a[i][j]=k;
        }
    }
    int res=Gauss(pn,n);
    //cout<<"res="<<res<<endl;
    if(res==-1) puts("0");
    else{
        printf("%I64d\n",(qpow(2LL,res,MOD)+MOD-1)%MOD);
    }
}

bool isP(int x)
{
    if(x==1) return 0;
    for(int i=2;i*i<=x;i++){
        if(x%i==0) return 0;
    }
    return 1;
}

void getPrime()
{
    pn=0;
    REP(i,2,2000){
        if(isP(i)) prime[pn++]=i;
    }
}

int main()
{
    //freopen("in.txt","r",stdin);
    int T;cin>>T;int casen=1;
    getPrime();
    while(T--){
        printf("Case #%d:\n",casen++);
        scanf("%d",&n);
        REP(i,0,n-1) scanf("%I64d",&b[i]);
        solve();
    }
    return 0;
}
View Code

1003:比較簡單的樹dp。ci

維護4個值,

 down[u]:從u向下走的最大值。

 down2[u]: 從u向下走而後回到u的最大值。

 up[u]: 從u向上走的最大值。

 up2[u]: 從u向上走而後回到u的最大值。

顯然答案就是: 先向下走而後回來再向上走,或者先向上走而後回來再向下走, max( down2[u]+up[u]-val[u], up2[u]+down[u]-val[u] )。

down2[u]的維護比較簡單: down2[u]= Sum( max(0, down2[v] -w*2) ) .

down[u] 也不難,好比停在子樹v上,那麼down[u]= max( down[v]-w+(down2[u]-val[u]) -(max(0,down2[v]-w*2)) .     

維護 up2[u]: 向上走到fa[u] ,而後向上走回來再向下走回來,可是向下走回來不能通過子樹u,只要用down2[fa[u]]- down2[u] 就好了。

維護 up[u] : 向上走到fa[u], 這時有兩種走法,先下後上或先上後下,先下後上的和up2[u]同理,向上後下的則須要判斷 down[fa[u]] 所停的子樹是否爲u,若是是,那麼就須要找次大的停,不然直接停在最大的,因此須要維護down的最大的和次大的點,在down的時候順便維護就好了。固然須要減去down2[u]-2*w。

很簡單的一道樹dp,比賽的時候因爲計算紙恰好用完沒把細節寫清楚就開始寫了,結果多開了兩個沒用的數組,調了好久沒調出來。。。

賽後改成直接枚舉fa的子樹,避開維護最大和次大,多了個常數,被卡了。回到宿舍在計算紙寫清楚細節後很快就A了。。。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

int n;
int val[maxn];
struct Node
{
    int v,w;
};vector<Node> G[maxn];
int u,v,w;
int down[maxn],down2[maxn],up[maxn],up2[maxn];
int first[maxn],second[maxn];
int fa[maxn],fw[maxn];

void dfs(int u,int f,int w)
{
    fa[u]=f;fw[u]=w;
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i].v,w=G[u][i].w;
        if(v==f) continue;
        dfs(v,u,w);
    }
}

int Down2(int u)
{
    int &res=down2[u];
    if(~res) return res;
    if(u==0) return res=0;
    res=0;
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i].v,w=G[u][i].w;
        if(v==fa[u]) continue;
        res+=max(0,-2*w+Down2(v));
    }
    res+=val[u];
    return res;
}

int Down(int u)
{
    int &res=down[u];
    if(~res) return res;
    if(u==0) return res=0;
    res=0;
    first[u]=second[u]=0;
    int sum=0;
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i].v,w=G[u][i].w;
        if(v==fa[u]) continue;
        sum+=max(0,-2*w+Down2(v));
    }
    int res2=0;/// second
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i].v,w=G[u][i].w;
        if(v==fa[u]) continue;
        int t=max(0,-w+Down(v)+sum-(max(0,-2*w+Down2(v))));
        if(t>res) res2=res,res=t,second[u]=first[u],first[u]=v;
        else if(t>res2) res2=t,second[u]=v;
    }
    //if(u==3) cout<<"sd2="<<second[u]<<endl;
    res+=val[u];
    return res;
}

int Up2(int u)
{
    int &res=up2[u];
    if(~res) return res;
    if(fa[u]==0) return res=val[u];
    res=-fw[u]*2+Up2(fa[u]);
    res+=Down2(fa[u])-max(0,Down2(u)-2*fw[u]);
    res-=val[fa[u]];
    res=max(0,res);
    res+=val[u];
    return res;
}

int Up(int u)
{
    int &res=up[u];
    if(~res) return res;
    if(fa[u]==0) return res=val[u];
    res=0;
    int A=0,B=0;/// A:up2->down  B:down2->up
    A=-fw[u]+Up2(fa[u]);
    //if(u==5) cout<<"A="<<A<<endl;
    int ft=first[fa[u]],sd=second[fa[u]];
    //if(u==5) cout<<"fa="<<fa[u]<<" ft="<<ft<<" sd="<<sd<<endl;
    if(ft==u) A+=Down2(fa[u])-max(0,Down2(u)-2*fw[u])-max(0,Down2(sd)-2*fw[sd])+max(0,Down(sd)-fw[sd]);
    else A+=Down2(fa[u])-max(0,Down2(u)-2*fw[u])-max(0,Down2(ft)-2*fw[ft])+max(0,Down(ft)-fw[ft]);
    A-=val[fa[u]];
    B=-fw[u]+Down2(fa[u])-max(0,Down2(u)-2*fw[u]);
    B+=Up(fa[u]);
    B-=val[fa[u]];
    //if(u==5) cout<<"A="<<A<<" B="<<B<<endl;
    res=(0,max(A,B));
    res+=val[u];
    return res;
}

void debug()
{
    REP(i,1,n) cout<<down[i]<<" ";cout<<endl;
    REP(i,1,n) cout<<down2[i]<<" ";cout<<endl;
    REP(i,1,n) cout<<up[i]<<" ";cout<<endl;
    REP(i,1,n) cout<<up2[i]<<" ";cout<<endl;
}

/**
1
5
4 1 7 7 7
1 2 6
1 3 1
2 4 8
3 5 2

 1
  6 1
 2    3
  8    2
 4    5
*/

int main()
{
    //freopen("in.txt","r",stdin);
    int T;cin>>T;int casen=1;
    while(T--){
        scanf("%d",&n);
        printf("Case #%d:\n",casen++);
        REP(i,1,n) scanf("%d",&val[i]);
        REP(i,0,n) G[i].clear(),down[i]=down2[i]=up[i]=up2[i]=-1;
        REP(i,1,n-1){
            scanf("%d%d%d",&u,&v,&w);
            G[u].push_back((Node){v,w});
            G[v].push_back((Node){u,w});
        }
        dfs(1,0,0);
        REP(i,1,n) Down2(i),Down(i);
        REP(i,1,n) Up2(i),Up(i);
        REP(u,1,n) printf("%d\n",max(down2[u]+up[u]-val[u],up2[u]+down[u]-val[u]));
        //debug();
    }
    return 0;
}
View Code

1008:簡單的計算幾何。

依次枚舉4個點,在枚舉前3個點的時候剪枝一下,而後枚舉第4個點直接判斷。

判斷條件,

  1, 4點不共面,混合積不爲0.

      2, 題目條件.

複雜度n^4,因爲n只有兩百,且加了剪枝以後很難達到n^4,因此。。。總之就是數據弱。。。

正解應該是:

   枚舉兩個點,在枚舉其它點判斷時候在其中垂面上,在中垂面上任選兩個點和原來的兩個點構成的正四面體必定合法,固然前提是這4點不共面。

  複雜度n^3。不過這種作法避不開double。

今天只寫了n^4的,n^3的明天再寫。

吐槽:隊友給讀這題的時候沒說n<=200啊。。。我覺得n<=1e5。。。坑。。。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

int n;
struct Point
{
    int x,y,z;
    friend Point operator-(Point A,Point B)
    {
        return {A.x-B.x,A.y-B.y,A.z-B.z};
    }
    friend ll operator*(Point A,Point B) /// 點乘
    {
        return A.x*B.x+A.y*B.y+A.z*B.z;
    }
};Point p[maxn];

Point chax(Point A,Point B) /// 叉乘
{
    return {A.y*B.z-A.z*B.y,A.z*B.x-A.x*B.z,A.x*B.y-A.y*B.x};
}

ll dist2(Point A,Point B)
{
    ll tx=A.x-B.x,ty=A.y-B.y,tz=A.z-B.z;
    return tx*tx+ty*ty+tz*tz;
}

ll jud(Point A,Point B,Point C)
{
    ll a=dist2(B,C),b=dist2(A,C),c=dist2(A,B);
    if(a!=b&&b!=c&&c!=a) return 0;
    if(a+b<=c&&b+c<=a&&a+c<=b) return 0;
    if(a==b) return a;
    if(b==c) return b;
    if(c==a) return c;
}

bool judge(Point A,Point B,Point C,Point D,ll dt)
{
    Point a=A-D,b=B-D,c=C-D;
    if(chax(a,b)*c==0) return 0;
    ll ab=dist2(A,B),ac=dist2(A,C),ad=dist2(A,D);
    ll bc=dist2(B,C),bd=dist2(B,D),cd=dist2(C,D);
    int cnt=0;
    if(ab==dt) cnt++;
    if(ac==dt) cnt++;
    if(ad==dt) cnt++;
    if(bc==dt) cnt++;
    if(bd==dt) cnt++;
    if(cd==dt) cnt++;
    if(cnt<4) return 0;
    if(cnt==5||cnt==6) return 1;
    if(ab!=dt&&cd!=dt) return 1;
    if(ac!=dt&&bd!=dt) return 1;
    if(ad!=dt&&bc!=dt) return 1;
    return 0;
}

int main()
{
    freopen("in.txt","r",stdin);
    int T;cin>>T;int casen=1;
    while(T--){
        scanf("%d",&n);
        REP(i,1,n) scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].z);
        ll res=0;
        REP(a,1,n){
            REP(b,a+1,n){
                REP(c,b+1,n){
                    ll dt=jud(p[a],p[b],p[c]);
                    if(dt==0) continue;/// 若是3條邊都不相等
                    REP(d,c+1,n){
                        if(judge(p[a],p[b],p[c],p[d],dt)) res++;
                    }
                }
            }
        }
        printf("Case #%d: %I64d\n",casen++,res);
    }
    return 0;
}
View Code

1007:待補。

1009:待補。

1010:待補。

 

總結:

    1, 原本應該是能夠6個題的,中間因爲計算紙恰好用完了,致使03細節沒寫清楚,而後一直卡在03,08只知道題意卻漏了最關鍵的數據範圍。。。

    2, 感受這場比賽和單挑沒什麼區別了,思路也是本身想的,代碼也全是本身寫的,除了03由於模數寫錯WA了一次其它都是1A。。。隊友的做用就是貢獻罰時,誤導題意,干擾思路的。

    3, 如今寫代碼的狀態應該算不錯了, 主要就是要調整好作題習慣,先想清楚細節再寫,寫完先測各類邊緣數據,其實只要作題習慣好點,單挑拿到名額應該是沒有什麼問題的。

相關文章
相關標籤/搜索