zoukankan      html  css  js  c++  java
  • [日常训练]常州集训day3

    T1

    Description

    有$K$个石子,石子只能放在$N$条水平线与$M$条竖直线构成的网格的交点上。
    求用$K$个石子最多能找到多少四边平行于坐标轴的长方形,它的四个角上都恰好放着一枚石子。

    Input

    第一行三个整数$N,M,K$。

    Output

    一个非负整数,即最多的满足条件的长方形数量。

    Sample Input

    3 3 8

    Sample Output

    5

    HINT

    $N;leq;30000$,保证任意两点不重合,$K;leq;N; imes;M$

    Solution

    很显然,最佳的方案长这样:

    $xxx…xxx$             $xxx…xxx$

    $xxx…xxx$             $xxx…xxx$

    ……           或      ….

    $xxx…xxx$             $xxx…xxx$

    $xxx…x$               $xxx…xxx$

    设上面两个图形的大多数行的个数为$l$,枚举$l$,$ans=max(c(k/l,2); imes;c(l,2)+c(k$%$l,2); imes;k/l)(1<l;leq;max(n,m))$。

    这题本弱有写过原题,但是考场上还是想错了QAQ

    #include<cmath>
    #include<ctime>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    ll n,m,k,sum,ans;
    inline bool chk(ll x,ll y){
        return max(x,y)<=n&&min(x,y)<=m;
    }
    inline ll c2(ll k){
        return k*(k-1)>>1;
    }
    inline void init(){
        scanf("%lld%lld%lld",&n,&m,&k);
        if(n<m){
            ll t=m;m=n;n=t;
        }
        for(ll i=n,x,y;i>1;i--){
            x=k/i;y=k%i;
            if(!chk(i,x+(y>0))||!x) continue;
            sum=c2(x)*c2(i)+c2(y)*x;
            ans=max(ans,sum);
        }
        printf("%lld
    ",ans);
    }
    int main(){
        freopen("rectangle.in","r",stdin);
        freopen("rectangle.out","w",stdout);
        init();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }

    T2

    Description

    求$Fibonacci$数列第$X-Y$项的和除以$10000$的余数。

    Input

    第一行一个整数$T$,表示数据组数。
    接下来$T$行,每行两个数$X,Y$,意义如题所述。

    Output

    $T$行,每行是一个询问的答案。

    Sample Input

    2
    1 5
    127 255

    Sample Output

    12
    5976

    HINT

    $T;leq;1000,X;leq;Y;leq;2^{31}−1$

    Solution

    $X,Y$这么大,很容易会想到矩乘。

    $s[i]=s[i-1]+f[i]=s[i-1]+f[i-1]+f[i-2]$。

    clip_image002[8]

    人生第一道当场A的矩乘题,感动QAQ

    #include<cmath>
    #include<ctime>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define M 10000
    using namespace std;
    struct matrix{
        int a[5][5],n,m;
    }a,b,c;
    int l,r,s1,s2,t;
    inline matrix mul(matrix a,matrix b){
        matrix c;c.n=a.n;c.m=b.m;
        for(int i=1;i<=c.n;i++)
            for(int j=1;j<=c.m;j++)
                c.a[i][j]=0;
        for(int i=1;i<=c.n;i++)
            for(int j=1;j<=c.m;j++)
                for(int k=1;k<=c.n;k++){
                    c.a[i][j]+=a.a[i][k]*b.a[k][j];
                    c.a[i][j]%=M;
                }
        return c;
    }
    inline matrix po(matrix a,int k){
        matrix c;c.m=a.m;c.n=a.n;
        for(int i=1;i<=c.n;i++)
            for(int j=1;j<=c.m;j++)
                if(i!=j) c.a[i][j]=0;
                else c.a[i][j]=1;
        while(k){
            if(k&1) c=mul(a,c);
            a=mul(a,a);k>>=1;
        }
        return c; 
    }
    inline void init(){
        scanf("%d",&t);
        a.m=a.n=b.n=3;b.m=1;
        a.a[1][1]=a.a[1][2]=a.a[1][3]=1;
        a.a[2][2]=a.a[2][3]=a.a[3][2]=1;
        b.a[1][1]=2;b.a[2][1]=b.a[3][1]=1;
        while(t--){
            scanf("%d%d",&l,&r);
            if(l<=3) s1=l-1;
            else{
                c=mul(po(a,l-3),b);
                s1=c.a[1][1];
            }
            if(r<=2) s2=r;
            else{
                c=mul(po(a,r-2),b);
                s2=c.a[1][1];
            }
            printf("%d
    ",(s2-s1+M)%M);
        }
    }
    int main(){
        freopen("fibonacci.in","r",stdin);
        freopen("fibonacci.out","w",stdout);
        init();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }

    T3

    Description

    给定一个$N$个顶点,$M$条边的无向连通图。

    设$dist1[i]$表示在这个无向连通图中,顶点$i$到顶点$1$的最短距离。

    求在这张图中,有多少棵大小为$N$的树满足对于任意的$i$,$dist1[i]=dist2[i]$($dist2[i]$表示在这棵树中,顶点$i$到顶点$1$的距离)。

    Input

    第一行,两个整数,$N,M$,表示有$N$个顶点和$M$条边。
    接下来有$M$行,每行有$3$个整数$x,y,len(1;leq;x,y;leq;n,1;leq;len;leq;100)$,
    表示顶点$x$和顶点$y$有一条长度为$len$的边。
    数据保证不出现自环、重边。

    Output

    一行两个整数,表示满足条件的方案数$mod;2147483647$的答案。

    Sample Input

    3 3
    1 2 2
    1 3 1
    2 3 1

    Sample Output

    2

    HINT

    $2;leq;N;leq;1000,N−1;leq;M;leq;N; imes;(N−1)/2$

    Solution

    $tot[i]$表示到达点$i$满足$dis2[j]+g[j][i]=dis2[i]$的点数。

    用$Dijkstra$实现即可。

    clip_image002[12]

    考场上记录答案的方式写错了导致炸到只剩20QAQ

    #include<cmath>
    #include<ctime>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define N 1005ll
    #define M 1000005ll
    #define K 2147483647ll
    using namespace std;
    typedef long long ll;
    struct graph{
        ll nxt,to,w;
    }e[M];
    ll g[N],dis[N],tot[N],n,m,ans,cnt;
    bool v[N];
    inline ll read(){
        ll ret=0;char c=getchar();
        while(!isdigit(c))
            c=getchar();
        while(isdigit(c)){
            ret=ret*10+c-'0';
            c=getchar();
        }
        return ret;
    }
    inline void addedge(ll x,ll y,ll w){
        e[++cnt].nxt=g[x];g[x]=cnt;
        e[cnt].to=y;e[cnt].w=w;
    }
    inline void init(){
        n=read();m=read();
        for(ll i=1,j,k,l;i<=m;i++){
            j=read();k=read();l=read();
            addedge(j,k,l);addedge(k,j,l);
        }
        for(ll i=2;i<=n;i++){
            dis[i]=M;tot[i]=1;
        }
        for(ll l=1,p=1,nxt,mi;l<=n;l++,p=nxt){
            for(ll i=g[p];i;i=e[i].nxt)
                if(dis[p]+e[i].w<dis[e[i].to]){
                    tot[e[i].to]=1;
                    dis[e[i].to]=dis[p]+e[i].w;
                }
                else if(dis[p]+e[i].w==dis[e[i].to])
                    tot[e[i].to]=(tot[e[i].to]+1)%K;
            mi=M;
            for(ll i=2;i<=n;i++)
                if(dis[i]<mi&&!v[i]){
                    mi=dis[i];nxt=i;
                }
            v[nxt]=true;
        }
        ans=1;
        for(ll i=2;i<=n;i++)
            ans=ans*tot[i]%K;
        printf("%I64d
    ",ans);
    }
    int main(){
        freopen("treecount.in","r",stdin);
        freopen("treecount.out","w",stdout);
        init();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    Android使用SQLite数据库(2)
    Android使用SQLite数据库(1)
    使用Eclipse为Android定义style
    SharedPreferences写入和读出数据
    AlertDialog.Builder弹出对话框
    Android退出时关闭所有Activity的方法
    获取PC或移动设备的所有IP地址
    Android文件的分割和组装
    到底什么是跨域?附解决方案!
    超详细 Nginx 极简教程
  • 原文地址:https://www.cnblogs.com/AireenYe/p/5774689.html
Copyright © 2011-2022 走看看