JXNU 2015-11

1001
由于 G 为 a,b 的最大公约数,那么 G 肯定是 a 的约数。由于 L 为 a,b 的最小公倍数,那么 L 肯定是 a 的倍数,也就是说 a 是 L 的约数。
既然 G 是 a 的约数,a 是 L 的约数,那么,G 必然是 L 的约数。如果 L 不能被 G 整除,那么必然不存在满足条件的 a,b
如果 L 能被 G 整除,那么由于 G<=a<=L,G<=b<=L.则满足条件的最小的 a 必然是 G,此时 b 必然等于 L。
故只要判断 L 是否能被 G 整除即可。直接上高精度除法模板,或 JAVA 大数搞之。

1002

首先,m>n 必然会冲突,直接输出 0

考虑 m<=n 的情形,很容易发现 ans=A(n,m)*C(n,m)

1003

直接模拟即可,可以 dfs 实现,也可以直接非递归实现

1004

1001~1004 并不是我出的题,验题的时候我是这样做的,以 O(n^3)的复杂度

暴力出前 20 个数的结果,然后发现有规律,至于规律具体是什么 ,直接
http://oeis.org/之(一个找数列规律的网站,很强大,很多题在推不出公式的情况
下可以这么搞)

1005

难度定位:中等题

归类:数学题
复杂度:O(n)
事实上,行列式可以化简成 a[1]*x^(n-1)+a[2]*x^(n-2)+...+a[n-1]*x^1+a[n]
如果直接算 a[1]*x^(n-1)%mod,需要用快速幂。
这里完全可以以 o(n)的复杂度先预处理出 x^i,(0<=i<=n-1)
然后再以 o(n)的复杂度 ans+=a[i]*x[n-i]即可,(1<=i<=n)

故总复杂度 O(n)

1006
难度定位:中等题
归类:线段树||树状数组
复杂度:O(n*log(n))
由于 i<j<k,a[i]<=a[j]<=a[k]最快的方法便是枚举 a[j],对于 a[j],如果能快速求出前面有多少个数比它小(逆序数),后面有多少个数比它大就好了。恰好,我们可以用线段树维护,并快速求
出。具体做法如下:
第一步,由于数据比较大,故离散化之(离散化三步走,排序,去重,二分)。(这部分复杂度 O(n*log(n)))
第二步,定义 left,right 数组,left[i],意为在 i 前面有多少个数小于等于 a[i],right[i],在 i 后面有多少个数大于等于 a[i]。那么如何求他们呢?例如求 left 数组,
从前往后枚举 i,对于 a[i],假设他离散化后的位置是 p,那么在线段树中查询区间[1,p]的和即可(即为小于等于 a[i]数的个数),然后,更新线段树维护 p 点的区间
的值即可。right 数组求法类似。只不过要从后往前枚举 i。 (这部分也是 O(n*log(n)))
其实上面的做法就是线段树||树状数组求逆序数的思想。
第三步,由乘法原理可知,枚举 i,然后 ans+=left[i]*right[i]即可。(这部分 O(n))
故总复杂度 O(n*log(n))
1007
难度定位:简单题
归类:模拟题
复杂度:O(n)
先把开奖的号码用数组 hash 一下。
对于每组数据与开奖比对,只需要到 hash 数组中查询即可。
1008
难度定位:难题
归类:最小费用最大流
复杂度:O(n^3)
题意:
给定一个有向图,必须用若干个环来覆盖整个图,要求这些覆盖的环的权值最小。
思路:
最小费用最大流,复杂度 O(n^3)
原图每个点 u 拆为 u 和 u' ,从源点引容量为 1 费用为 0 的边到 u ,从u' 引相同性质的边到汇点,若原图中存在 (u, v) ,则从 u 引容量为 1 费用为
c(u, v) 的边到 v' 。这里源模拟的是出度,汇模拟的是入度,又每个点的出度等于入度等于 1 ,那么如果最大流不等于顶点数 n ,则无解;否则,答案就是最小费用。

1001

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int L=210;
int sub(int *a,int *b,int La,int Lb)
{
    if(La<Lb) return -1;//如果a小于b,则返回-1
    if(La==Lb)
    {
        for(int i=La-1;i>=0;i--)
            if(a[i]>b[i]) break;
            else if(a[i]<b[i]) return -1;//如果a小于b,则返回-1

    }
    for(int i=0;i<La;i++)//高精度减法
    {
        a[i]-=b[i];
        if(a[i]<0) a[i]+=10,a[i+1]--;
    }
    for(int i=La-1;i>=0;i--)
        if(a[i]) return i+1;//返回差的位数
    return 0;//返回差的位数

}
string div(string n1,string n2,int nn)//n1,n2是字符串表示的被除数,除数,nn是选择返回商还是余数
{
    string s,v;//s存商,v存余数
     int a[L],b[L],r[L],La=n1.size(),Lb=n2.size(),i,tp=La;//a,b是整形数组表示被除数,除数,tp保存被除数的长度
     fill(a,a+L,0);fill(b,b+L,0);fill(r,r+L,0);//数组元素都置为0
     for(i=La-1;i>=0;i--) a[La-1-i]=n1[i]-'0';
     for(i=Lb-1;i>=0;i--) b[Lb-1-i]=n2[i]-'0';
     if(La<Lb || (La==Lb && n1<n2)) {
            //cout<<0<<endl;
     return n1;}//如果a<b,则商为0,余数为被除数
     int t=La-Lb;//除被数和除数的位数之差
     for(int i=La-1;i>=0;i--)//将除数扩大10^t倍
        if(i>=t) b[i]=b[i-t];
        else b[i]=0;
     Lb=La;
     for(int j=0;j<=t;j++)
     {
         int temp;
         while((temp=sub(a,b+j,La,Lb-j))>=0)//如果被除数比除数大继续减
         {
             La=temp;
             r[t-j]++;
         }
     }
     for(i=0;i<L-10;i++) r[i+1]+=r[i]/10,r[i]%=10;//统一处理进位
     while(!r[i]) i--;//将整形数组表示的商转化成字符串表示的
     while(i>=0) s+=r[i--]+'0';
     //cout<<s<<endl;
     i=tp;
     while(!a[i]) i--;//将整形数组表示的余数转化成字符串表示的</span>
     while(i>=0) v+=a[i--]+'0';
     if(v.empty()) v="0";
     //cout<<v<<endl;
     if(nn==1) return s;
     if(nn==2) return v;
}
int main()
{
    string a,b;
    while(cin>>a>>b)
    {
        //cout<<div(a,b,1)<<endl;
        //cout<<div(a,b,2)<<endl;
        string ans=div(b,a,2);
        if(ans!="0") cout<<-1<<endl;
        else cout<<a<<" "<<b<<endl;
    }
    return 0;
}

1002

#include<iostream>
#include<cstdio>
#define ULL unsigned long long
using namespace std;
const int maxn=35;
ULL dp[maxn][maxn*maxn];
ULL C(int n,int m)
{
    if(n<m) return 0;
    ULL ans=1;
    for(int i=0;i<m;i++) ans=ans*(ULL)(n-i)/(ULL)(i+1);
    return ans;
}
ULL A(int n,int m)
{
    if(n<m) return 0;
    ULL ans=1;
    for(int i=0;i<m;i++) ans*=(ULL)(n-i);
    return ans;
}
ULL fuck(int n,int k)
{
    if(dp[n][k]) return dp[n][k];
    return dp[n][k]=A(n,k)*C(n,k);
}
int main()
{
    //freopen("in.txt","r",stdin);
    int n,k,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        printf("%I64u\n",fuck(n,k));
        //printf("%I64u\n",A(n,k));
        //printf("%I64u\n",C(n,k));
    }
    return 0;
}

1003

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=105;
int a[maxn][maxn];
void dfs(int x,int y,int n,int m,int num)
{
    if(n==0||m==0) return ;
    if(n==1)
    {
        for(int i=0;i<m;i++) a[x][y+i]=num++;
        return ;
    }
    if(m==1)
    {
        for(int i=0;i<n;i++) a[x+i][y]=num++;
        return ;
    }
    for(int i=0;i<m;i++) a[x][y+i]=num++;
    for(int i=1;i<n-1;i++) a[x+i][y+m-1]=num++;
    for(int i=m-1;i>=0;i--) a[x+n-1][y+i]=num++;
    for(int i=n-2;i>0;i--) a[x+i][y]=num++;
    dfs(x+1,y+1,n-2,m-2,num);
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        dfs(0,0,n,m,1);
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m-1;j++) printf("%d ",a[i][j]);
            printf("%d\n",a[i][m-1]);
        }
    }
    return 0;
}

1004
<pre name="code" class="cpp">#include<iostream>
#include<cstdio>
#define LL long long
using namespace std;
const int maxn=1000005;
LL dp[maxn];
int main()
{
    //dp[0]=1;
    //dp[1]=3;
    //dp[2]=3;
   // for(int i=2;i<maxn;i++) dp[i]=dp[i-2]+(LL)i*(LL)(i-1)/2;
    LL n;
    while(~scanf("%I64d",&n)) //printf("%d\n",dp[n-3]);
    {
        n-=4;
        LL ans=(n+2)*(n+4)*(2*n+3) / 24;
        printf("%I64d\n",ans);
    }
    return 0;
}
 

1005

<pre name="code" class="cpp">#include<iostream>
#include<cstdio>
#define LL long long
using namespace std;
const int maxn=100005;
const LL mod=1000000007;
int a[maxn];
LL X[maxn];
int main()
{
   // freopen("in.txt","r",stdin);
   // freopen("out.txt","w",stdout);
    int t,n,x;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&x);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        X[0]=1;
        for(int i=1;i<n;i++) X[i]=(X[i-1]*x)%mod;//预处理出所有的x^i
        LL ans=0;
        for(int i=0;i<n;i++)
            ans=(ans+X[i]*a[n-i])%mod;
        printf("%I64d\n",ans);
    }
    return 0;
}

 

1006

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn=100005;
int a[maxn],b[maxn],Left[maxn],Right[maxn];
int sum[maxn<<2];
void PushUp(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]=0;
        return ;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    PushUp(rt);
}
void update(int p,int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]++;
        return ;
    }
    int m=(l+r)>>1;
    if(p<=m) update(p,lson);
    else update(p,rson);
    PushUp(rt);
}
int query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        return sum[rt];
    }
    int m=(l+r)>>1;
    int ans=0;
    if(L<=m) ans+=query(L,R,lson);
    if(R>m) ans+=query(L,R,rson);
    return ans;
}
int main()
{
   // freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%d",&a[i]),b[i]=a[i];
        sort(b,b+n);//离散化第一步
        int lb=unique(b,b+n)-b;//离散化第二步
        build(1,lb,1);//由于离散化后a[i]的范围为[1,lb],故建立一颗维护[1,lb]的和的线段树
        for(int i=0;i<n;i++)
        {
            int p=upper_bound(b,b+lb,a[i])-b;//离散化第三步
            Left[i]=query(1,p,1,lb,1);//查询出小于等于a[i]的数的个数,类似于线段树求逆序数的原理
            update(p,1,lb,1);//插入第i个数
        }
        build(1,lb,1);
        for(int i=n-1;i>=0;i--)
        {
            int p=upper_bound(b,b+lb,a[i])-b;
            Right[i]=query(p,lb,1,lb,1);
            update(p,1,lb,1);
        }
        LL ans=0;
        for(int i=0;i<n;i++)
        {
            ans+=(LL)Left[i]*(LL)Right[i];
            //printf("%d %d\n",Left[i],Right[i]);
        }
        printf("%I64d\n",ans);
    }
    return 0;
}
1007
#include<iostream>
#include<cstdio>
#define LL long long
using namespace std;
int a[100005][8];
int b[8];
int vis[40];
int n;
int ans[10][10];
void SetValue()
{
    ans[6][1]=5000000;ans[6][0]=500000;
    ans[5][1]=3000;ans[5][0]=200;
    ans[4][1]=200;ans[4][0]=10;
    ans[3][1]=10;ans[2][1]=5;
    ans[1][1]=5;ans[0][1]=5;
}
void solve()
{
    fill(vis,vis+40,0);
    for(int i=0;i<6;i++) vis[b[i]]=1;
    LL sum=2*n;
    for(int i=0;i<n;i++)
    {
        int k=0,p;
        for(int j=0;j<6;j++) k+=vis[a[i][j]];
        p=(a[i][6]==b[6]);
        sum-=ans[k][p];
    }
    printf("%I64d\n",sum);
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    SetValue();
    int t;
    scanf("%d",&t);
    while(t--)
    {
        for(int i=0;i<7;i++) scanf("%d",&b[i]);
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            for(int j=0;j<7;j++)
            scanf("%d",&a[i][j]);
        solve();
    }
    return 0;
}

1008

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<sstream>
#include<fstream>
#include<vector>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<queue>
#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1 | 1
using namespace std;
const int maxn=100005,inf=1<<29;
int n,m,V;
typedef pair<int,int>P;
struct edge{ int to,cap,cost,rev;};
vector<edge>G[maxn];
int h[maxn];//¶¥μãμÄêÆ
int dist[maxn];//×î¶ì¾ààë
int prevv[maxn],preve[maxn];
void add_edge(int from,int to,int cap,int cost)
{
    G[from].push_back((edge){to,cap,cost,G[to].size()});
    G[to].push_back((edge){from,0,-cost,G[from].size()-1});
}
void Dijkstra(int s,int t)
{
    priority_queue<P,vector<P>,greater<P> >q;
    fill(dist,dist+V,inf);
    dist[s]=0;
    q.push(P(0,s));
    while(q.size())
    {
        P p=q.top();q.pop();
        int v=p.second;
        if(dist[v]<p.first) continue;
        for(int i=0;i<G[v].size();i++)
        {
            edge &e=G[v][i];
            if(e.cap>0&&dist[e.to]>dist[v]+e.cost+h[v]-h[e.to])
            {
                dist[e.to]=dist[v]+e.cost+h[v]-h[e.to];
                prevv[e.to]=v;
                preve[e.to]=i;
                q.push(P(dist[e.to],e.to));
            }
        }
    }
}
int min_cost_flow(int s,int t,int f)
{
    int res=0;
    fill(h,h+V,0);
    while(f>0)
    {
        Dijkstra(s,t);
        if(dist[t]==inf) return -1;
        for(int v=0;v!=V;v++) h[v]+=dist[v];
        int d=f;
        for(int v=t;v!=s;v=prevv[v]) d=min(d,G[prevv[v]][preve[v]].cap);
        f-=d;
        res+=d*h[t];
        for(int v=t;v!=s;v=prevv[v])
        {
            edge &e=G[prevv[v]][preve[v]];
            e.cap-=d;
            G[v][e.rev].cap+=d;
        }
    }
    return res;
}
int main()
{
    //freopen("in.txt","r",stdin);
   // freopen("out.txt","w",stdout);
    while(~scanf("%d%d",&n,&m))
    {
        V=2*n+2;
        for(int i=0;i<=V;i++) G[i].clear();
        int s=0,t=2*n+1;
        for(int i=1;i<=n;i++) add_edge(s,i,1,0);
        for(int i=1;i<=n;i++) add_edge(i+n,t,1,0);
        while(m--)
        {
            int x,y,w;
            scanf("%d%d%d",&x,&y,&w);
            add_edge(x,y+n,1,w);
        }
        printf("%d\n",min_cost_flow(s,t,n));
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值