查找第k小的数

【问题描述】
    帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij,均
为非负整数。游戏规则如下:
1.每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素;
2.每次取走的各个元素只能是该元素所在行的行首或行尾;
3.
每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分=被取走的元素值*2^i,其中i表示第i次取数(从1开始编号);
4. 游戏结束总得分为m次取数得分之和。
帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

简单题

查找第k小的数

【输入格式】

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)

问题描述:给定n个元素,要求从中找出第k小的元素。

    输入文件game.in包括n+1行:
第1行为两个用空格隔开的整数n和m。
第2-n+l行为n*m矩阵,其中每行有m个用单个空格隔开的非负整数。

Total Submission(s) : 19   Accepted Submission(s) : 14

文件输入:第一行两个整数:第一个是n表示有n个正整数(n<=50000),第二个整数k表示要查找第k小的元素;
  第二行有n 个用空格隔开的整数。

【输出格式】
   输出文件game.out仅包含1行,为一个整数,即输入矩阵取数后的最大得分。

Font: Times New Roman | Verdana | Georgia

文件输出:一个整数,第一个表示第k 小的元素的值。

【输入输出样例1】
  输入:
2 3
1 2 3
3 4 2

Font Size: ← →

大吉大利今晚吃鸡

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K
(Java/Other)

Total Submission(s) : 1379   Accepted Submission(s) : 501

Font: Times New Roman | Verdana | Georgia

Font Size: ← →

Problem Description

最近流行吃鸡,那就直接输出一行”Winner winner ,chicken
dinner!”(没有双引号)
模板代码:
#include <stdio.h>
int main(){
printf(“hello worldn”);
return 0;
}

Input

没有输入

Output

输出一行”Winner winner ,chicken dinner!”注意要换行

Sample Output

Winner winner ,chicken dinner!

解题报告:

签到题

#include <stdio.h>
int main(){
printf(“Winner winner ,chicken dinner!n”);
return 0;
}

 

1002      

跳舞

Time Limit : 3000/1500ms (Java/Other)   Memory Limit : 65535/32768K
(Java/Other)

Total Submission(s) : 354   Accepted Submission(s) : 38

Font: Times New Roman | Verdana | Georgia

Font Size: ← →

Problem Description

一天YZW参加了学校组织交际舞活动,活动的开始活动方分别给男生和女生从1-n进行编号,按照从小到大顺时针的方式进行男女搭档分配,相同编号的男女组合成一对,例如一号男生与一号女生配对,以此类推。可是YZW对其中一个小姐姐一见钟情,于是机智的他向管理员提出了两种操作
1.在这种情况下,管理员会给出移动的方向和大小,然后所有的男生向着这个方向移动x个位置。2.管理员会把相邻的奇数和偶数位置上的男生互换。
在其中女生的位置是不会变的。可是YZW不知道经过这些Q次操作后,他自己身在何方,能否到达自己喜欢的小姐姐身边。

Input

输入一个T代表T组数据(T<=10),每组输入一个n和q(2≤n≤200000,1≤q≤1000000,其中n为偶数),分别代表有n对男女和有q次操作。
接下来是q行,每一行输入:
1.x代表所有男生移动的位置的大小。同时x>0表示顺时针移动,x<0表示逆时针移动。
2.代表管理员会把相邻的奇数和偶数位置上的男生互换。

Output

输出1号到n号小姐姐配对的分别是几号男生。

Sample Input

1

6 3

1 2

2

1 2

Sample Output

4 3 6 5 2 1

 

解题报告:记录第一个和第二个男生的位置n1和n2,将所有的操作的影响加在这个两位置上,其中第一种操作相当于n1和n2加上或者减去x,第二种操作相当于奇数位置上的数+1,偶数位上的数-1.然后通过这样两个位置推导出所有的其他的位置即可

代码:

#include<iostream>

#include<cstdio>

#include<cmath>

#include<string>

#include<queue>

#include<algorithm>

#include<stack>

#include<cstring>

#include<vector>

#include<list>

#include<bitset>

#include<set>

#include<map>

using namespace std;

#define LL long long

#define pi (4*atan(1.0))

#define eps 1e-8

#define bug(x)  cout<<“bug”<<x<<endl;

const int N=1e6+10,M=7e6+10,inf=1e9+10,MOD=10;

const LL INF=1e18+10;

 

int a[N];

int main()

{

    int T;

    scanf(“%d”,&T);

    while(T–)

    {

        int n,q;

        scanf(“%d%d”,&n,&q);

        int s=1,e=2;

        while(q–)

        {

            int t;

            scanf(“%d”,&t);

            if(t==1)

            {

                LL x;

                scanf(“%lld”,&x);

                x%=n;

                s+=x;

                e+=x;

                if(s>n)s-=n;

                if(s<=0)s+=n;

                if(e>n)e-=n;

                if(e<=0)e+=n;

            }

            else

            {

                if(s%2)s++;

                else s–;

                if(e%2)e++;

                else e–;

            }

        }

        for(int i=1;i<=n/2;i++)

        {

            a[s]=i*2-1;

            a[e]=i*2;

            s+=2;

            e+=2;

            if(s>n)s-=n;

            if(e>n)e-=n;

        }

        for(int i=1;i<=n;i++)

            printf(“%d%c”,a[i],(i==n?’n’:’ ‘));

    }

    return 0;

}

1003

这是道水题

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K
(Java/Other)

Total Submission(s) : 827   Accepted Submission(s) : 179

Font: Times New Roman | Verdana | Georgia

Font Size: ← →

Problem Description

有两个球在长度为L的直线跑道上运动,两端为墙。0时刻小球a以1m/s的速度从起点向终点运动,t时刻小球b以相同的速度从终点向起点运动。问T时刻两球的距离。这里小球与小球、小球与墙的碰撞均为弹性碰撞,所有过程没有能量损失。

Input

先输入一个q,代表q组数据,然后每组3个整数 L,t,T。
1<=L<=1000;0<=t<=1000;t<=T<=1000;

Output

一个整数,代表答案。

Sample Input

2

10 4 7

8 3 9

Sample Output

0

5

解题报告:单独考虑每个小球,分别求出最后小球的位置pos1,pos2。答案即为abs(pos1-pos2)。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

int main()
{
    int L,t,T;
    int cas;
    scanf(“%d”,&cas);
    while(cas–&&scanf(“%d %d %d”,&L,&t,&T)){
        int n=T%(2*L);
        int l;
        if(n>=L){
            l=L-(n-L);
        }else{
            l=n;
        }
        int r;
        int n2=(T-t)%(2*L);
        if(n2>=L){
            r=L-(n2-L);
        }else{
            r=n2;
        }
        r=L-r;
        int ans=r-l;
        if(ans>=0){
            printf(“%dn”,ans);
        }else{
            printf(“%dn”,-1*ans);
        }
    }
    return 0;
}

 

1004

 

小廖的美丽子串

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K
(Java/Other)

Total Submission(s) : 7   Accepted Submission(s) : 0

Font: Times New Roman | Verdana | Georgia

Font Size: ← →

Problem Description

小廖最近沉迷于字符串,发现了一个问题,不能解决,非常懊恼。你能帮助他吗?
对于一个长度为n的字符串,可以从大小为m的字母表里选取构成。
定义一个字符串是美丽的就满足:如果它的所有字符适当改变顺序后能够组成一个回文串并且长度为奇数。
那么问题来了,大小为m的字母表组成的所有大小为n的串有m^n个,其包含美丽的子串的总和是多少?

Input

首先输入一个t,代表t组数据t<=100
每组数据输入n,m,n代表字符串的长度,m代表字母表的大小。
1<=n,m<=2000

Output

输出结果mod1000000007。(mod表示取余)

Sample Input

3

2 2

3 2

10 3

Sample Output

8

32

1490526


解题报告:

设dp[i][j]表示长度为i的串有j种字符出现奇数次的个数。

dp[i][j]只能由dp[i-1][j-1]和dp[i-1][j+1]转化来。

假如长度为i-1的串有j-1种字符出现奇数次,可以在剩余的(m-j+1)种字符选取一个;

假如长度为i-1的串有j+1种字符出现奇数次,可以在(j+1)种字符里任选一个;

所以状态转移方程为:
dp[i][j]=(dp[i-1][j-1]*(m-j+1)+dp[i-1][j+1]*(j+1))

注意若能组成回文串,当长度为奇数时j=1,否则j=0.

枚举奇数长度i的串,其位置可以有(n-i+1)种,其它n-i位任意补齐,所以对于长度为i有

dp[i][1]*p[n-i]*(n-i+1)个,p[n-i]表示m的n-i次方。累加求和得到

ans=(ans+dp[i][i&1]*po[n-i]%mod*(n-i+1)%mod)%mod;

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<queue>
#include<algorithm>
#include<stack>
#include<cstring>
#include<vector>
#include<list>
#include<bitset>
#include<set>
#include<map>
#include<time.h>
#define F(x) (3*x*x-x)/2
using namespace std;
typedef long long ll;
const int maxn=2000+10;
const int mod=1e9+7;
int n,m;
ll dp[maxn][maxn],po[maxn];
int main()
{
    int t;
    scanf(“%d”,&t);
    while(t–)
    {
        scanf(“%d%d”,&n,&m);
        dp[0][0]=1;dp[0][1]=0;
        for(int i=1;i<=n;i++)
        {
            dp[i][0]=dp[i-1][1];
            dp[i][i]=(dp[i-1][i-1]*(m-i+1))%mod;
            int j;
            if(i&1)j=1;
            else j=2;
            for(;j<i;j+=2)
            {
                dp[i][j]=(dp[i-1][j-1]*(m-j+1)+dp[i-1][j+1]*(j+1))%mod;
            }
        }
        po[0]=1;
        for(int i=1;i<=n;i++)
        po[i]=(po[i-1]*m)%mod;
        ll ans=0;
        for(int i=1;i<=n;i++)
        {
                    if(i%2)
            ans=(ans+dp[i][i&1]*po[n-i]%mod*(n-i+1)%mod)%mod;
        }
        printf(“%lldn”,ans);
    }
    return 0;
}

 

1005      

矩阵

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K
(Java/Other)

Total Submission(s) : 168   Accepted Submission(s) : 52

Font: Times New Roman | Verdana | Georgia

Font Size: ← →

Problem Description

假设你有一个矩阵,有这样的运算A^(n+1) = A^(n)*A (*代表矩阵乘法)
现在已知一个n*n矩阵A,S =
A+A^2+A^3+…+A^k,输出S,因为每一个元素太大了,输出的每个元素模10

Input

先输入一个T(T<=10),每组一个n,k(1<=n<=30, k<=1000000)

Output

输出一个矩阵,每个元素模10(行末尾没有多余空格)

Sample Input

1

3 2

0 2 0

0 0 2

0 0 0

Sample Output

0 2 4

0 0 2

0 0 0

解题报告:

倍增,复杂度log(k)*n*n

代码:

#include<iostream>

#include<cstdio>

#include<cmath>

#include<string>

#include<queue>

#include<algorithm>

#include<stack>

#include<cstring>

#include<vector>

#include<list>

#include<bitset>

#include<set>

#include<map>

using namespace std;

#define LL long long

#define pi (4*atan(1.0))

#define eps 1e-8

#define bug(x)  cout<<“bug”<<x<<endl;

const int N=1e6+10,M=7e6+10,inf=1e9+10,MOD=10;

const LL INF=1e18+10;

int n;

struct Matrix

{

    short a[31][31];

    Matrix()

    {

        memset(a,0,sizeof(a));

    }

    void init()

    {

        for(int i=0;i<n;i++)

            for(int j=0;j<n;j++)

                a[i][j]=(i==j);

    }

    Matrix operator + (const Matrix &B)const

    {

        Matrix C;

        for(int i=0;i<n;i++)

            for(int j=0;j<n;j++)

                C.a[i][j]=(a[i][j]+B.a[i][j])%MOD;

        return C;

    }

查找第k小的数。    Matrix operator * (const Matrix &B)const

    {

        Matrix C;

        for(int i=0;i<n;i++)

            for(int k=0;k<n;k++)

                for(int j=0;j<n;j++)

                   
C.a[i][j]=(C.a[i][j]+a[i][k]*B.a[k][j])%MOD;

        return C;

    }

    Matrix operator ^ (const int &t)const

    {

        Matrix A=(*this),res;

        res.init();

        int p=t;

        while(p)

        {

            if(p&1)res=res*A;

            A=A*A;

            p>>=1;

        }

        return res;

    }

}a[100],base;

 

int main()

{

    int T;

    scanf(“%d”,&T);

    while(T–)

    {

        int k;

        scanf(“%d%d”,&n,&k);

        for(int i=0;i<n;i++)

        for(int j=0;j<n;j++)

        scanf(“%d”,&a[1].a[i][j]);

        base=a[1];

        for(int i=2;i<=20;i++)

        {

            a[i]=a[i-1]+(a[i-1])*base;

            base=base*base;

        }

        base=a[1];

        Matrix now,ans;

        now.init();

        for(int i=19;i>=0;i–)

        {

            if((1<<i)&k)

            {

                ans=ans+a[i+1]*now;

                now=now*(base^(1<<i));

            }

        }

        for(int i=0;i<n;i++)

        {

            for(int j=0;j<n;j++)

                printf(“%d%c”,ans.a[i][j],(j==n-1?’n’:’ ‘));

        }

    }

    return 0;

}

1006      

大厦

Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 65535/32768K
(Java/Other)

Total Submission(s) : 41   Accepted Submission(s) : 2

Font: Times New Roman | Verdana | Georgia

Font Size: ← →

Problem Description

给你一个n(1<=n<=1000)层楼的大厦,每一楼里面有m(1<=m<=1000)房间,
每个房间一定的金钱X(1<=x<=1000),假设不同楼层的房间是互通的,相同楼层的房间是不互通的。也就是说每层只能取一个,现在给你一个捡钱的机会。捡钱的方式不同,会导致你得到的钱的不同,求可能捡到的钱的前k大的和

Input

输入一个T,表示T组样例;
每组数据第一行输入n,m,k
接下来输入n行,每行m个数,代表这个房间拥有的金钱

Output

输出可能捡到的钱的前k大的和

Sample Input

1

3 4 5

1 2 3 4

5 6 7 8

1 2 3 4

Sample Output

75

解题报告:

假设任意两层为集合A
B(从大到小排序)对于B集合的元素B[i],显然它和A[1]组合值最大,

如果B[i]+A[j]是前K大值中的一个,那么B[i]+A[k](1<=k <
j)必然也是前K大的,

所以B[i]+A[j]被选则B[i]+A[j-1]之前就被选了,

所以优先队列中只需维护Size(B)个元素,首先把A[1]+B[i]全部进队,

每次从队首拿出一个组合(i,j)(表示A[i]+B[j]),把A[i+1]+B[j]进队,

直到拿出K个元素为止,即为这两个集合合并的前K大

n层的话只要把每次得到的结果和其他层按照这样处理就可以了

代码:

#include<iostream>

#include<cstdio>

#include<cmath>

#include<string>

#include<queue>

#include<algorithm>

#include<stack>

#include<cstring>

#include<vector>

#include<list>

#include<bitset>

#include<set>

#include<map>

using namespace std;

#define LL long long

#define pi (4*atan(1.0))

#define eps 1e-8

#define bug(x)  cout<<“bug”<<x<<endl;

const int N=1e3+10,M=7e6+10,inf=1e9+10,MOD=10;

const LL INF=1e18+10;

 

 

int a[N],k,n,m;

vector<int>v;

struct is

{

    int x,pos;

    is(){}

    is(int _x,int _pos):x(_x),pos(_pos){}

    bool operator <(const is &c)const

    {

        return x<c.x;

    }

};

int cmp(int x,int y)

{

    return x>y;

}

vector<int> update(vector<int>v)

{

    vector<int>ans;

    if(v.size()*m<=k)

    {

        for(int i=0;i<v.size();i++)

        for(int j=1;j<=m;j++)

            ans.push_back(v[i]+a[j]);

        sort(ans.begin(),ans.end(),cmp);

    }

    else

    {

        priority_queue<is>q;

        for(int i=1;i<=m;i++)

        {

            q.push(is(a[i]+v[0],0));

        }

        int tmp=k;

        while(tmp–)

        {

            is x=q.top();

            ans.push_back(x.x);

            q.pop();

            if(x.pos+1<v.size())

            q.push(is(x.x-v[x.pos]+v[x.pos+1],x.pos+1));

        }

    }

    return ans;

}

int main()

{

    int T;

    scanf(“%d”,&T);

    while(T–)

    {

        scanf(“%d%d%d”,&n,&m,&k);

        v.clear();

        v.push_back(0);

        for(int i=1;i<=n;i++)

        {

            for(int j=1;j<=m;j++)

                scanf(“%d”,&a[j]);

            v=update(v);

        }

        LL ans=0;

        for(int i=0;i<k;i++)

            ans+=v[i];

        printf(“%lldn”,ans);

    }

    return 0;

}

1007      

超级牛奶

Time Limit : 6000/3000ms (Java/Other)   Memory Limit : 65535/32768K
(Java/Other)

Total Submission(s) : 52   Accepted Submission(s) : 6

Font: Times New Roman | Verdana | Georgia

Font Size: ← →

Problem Description

超市有 n 种牛奶,每种牛奶的浓度为 ai/1000 。
Alice 想合成出一种浓度为 k/1000
的超级牛奶,每种牛奶可以买任意杯,她最少需要买多少杯牛奶呢?

Input

多组输入,每组数据第一行输入 k、n ,第二行输入 n 个数ai,表示 n
种牛奶的浓度。
0<=k<=1000 , 1<=n<=1000000, 0<=ai<=1000 。
所给数据都是整数。

Output

每组数据输出一个数,表示最少要买多少杯牛奶。 如果无法合成浓度为 k/1000
的牛奶,就输出 -1 。

Sample Input

50 2

100 25

Sample Output

3

解题报告:要注意到浓度绝不会超过1000/1000。

假设选取m杯牛奶,则 (a1+a2+……+am) / m =
n,变换一下为(a1-n)+(a2-n)+……+(am-n) = 0。即要选 m杯牛奶,其浓度减
n之和为0。而浓度不超过1000,故(a1-n)+(a2-n)+….+(as-n)的和肯定在
-1000~1000之间,所以可以 bfs解,相当于找一条浓度0 到浓度0
的路径,边长为(ai-n),这样到每个可能浓度点的距离一定是最近的。

代码:

#include<iostream>

#include<cstdio>

#include<cmath>

#include<string>

#include<queue>

#include<algorithm>

#include<stack>

#include<cstring>

#include<vector>

#include<list>

#include<bitset>

#include<set>

#include<map>

using namespace std;

#define LL long long

#define pi (4*atan(1.0))

#define eps 1e-8

#define bug(x)  cout<<“bug”<<x<<endl;

const int N=1e3+10,M=7e6+10,inf=1e9+10,MOD=10;

const LL INF=1e18+10;

 

vector<int>v[5];

int flag[N][2];

int dp[N][2];

int main()

{

    int k,n;

    while(~scanf(“%d%d”,&k,&n))

    {

        v[0].clear();

        v[1].clear();

        memset(flag,0,sizeof(flag));

        memset(dp,-1,sizeof(dp));

        int fuck=0;

        for(int i=1;i<=n;i++)

        {

            int x;

            scanf(“%d”,&x);

            if(x==k)fuck=1;

           
if(x<k&&!flag[k-x][0])v[0].push_back(k-x),flag[k-x][0]=1;

           
if(x>k&&!flag[x-k][1])v[1].push_back(x-k),flag[x-k][1]=1;

        }

        if(fuck)

        {

            printf(“1n”);

            continue;

        }

        dp[0][0]=0;

        dp[0][1]=0;

        for(int kk=0;kk<=1;kk++)

        for(int i=0;i<v[kk].size();i++)

        {

            for(int j=v[kk][i];j<=1000;j++)

            {

                if(dp[j-v[kk][i]][kk]!=-1)

                {

                   
if(dp[j][kk]==-1)dp[j][kk]=dp[j-v[kk][i]][kk]+1;

                    else
dp[j][kk]=min(dp[j][kk],dp[j-v[kk][i]][kk]+1);

                }

            }

        }

        int ans=inf;

        for(int i=1;i<=1000;i++)

        if(dp[i][0]!=-1&&dp[i][1]!=-1)

        {

            ans=min(ans,dp[i][0]+dp[i][1]);

        }

        if(ans==inf)printf(“-1n”);

        else printf(“%dn”,ans);

    }

    return 0;

}

 

1008      

子序列

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K
(Java/Other)

Total Submission(s) : 499   Accepted Submission(s) : 270

Font: Times New Roman | Verdana | Georgia

Font Size: ← →

Problem Description

长度为 n
的序列,把它划分成两段非空的子序列,定义权值为:两段子序列的最大值的差的绝对值。求可能的最大的权值。
数据范围:
2 <= n <= 10^6 , 0 < 序列内的数 <= 10^6 。

Input

第一行输入一个 T,表示有 T 组数据。
接下来有 T 组数据,每组数据的第一行输入一个数 n ,第二行输入 n 个数。

Output

每组数据输出可能的最大的权值。

Sample Input

1

www.9778.com,3

1 2 3

Sample Output

2

解题报告:

签到题,代码:

#include<iostream>
#include<string.h>
#include<math.h>
using namespace std;
int a[1000010];
int main()
{
  int t;
  cin>>t;
  while(t–)
  {
   int maxn=0;int k,n;
   memset(a,0,sizeof(a));
   cin>>n;
   for(int i=1;i<=n;i++){
  
   cin>>a[i];
   if(a[i]>maxn)
   {
   maxn=a[i];
   k=i;
  }
  
  
                        }
    int k2;
    if(k!=1&&k!=n)
    k2=min(a[1],a[n]);
    else if(k==a[1])
    {
    
     k2=a[n];
    
}
else
k2=a[1];
cout<<maxn-k2<<endl;
  }
return 0;
}

 

1009

 

MDD的随机数

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K
(Java/Other)

Total Submission(s) : 61   Accepted Submission(s) : 28

Font: Times New Roman | Verdana | Georgia

Font Size: ← →

Problem Description

MDD随机生成了n(n<le5)个随机数x(x<=1e9),
这n个随机数排成一个序列,MDD有q(q<=le5)个询问,
每个询问给你一个a,问你这个序列中有多少个区间的最大公约数不为a

Input

第一行输入一个T,表示T组测试样例
每组样例包含一个n,表示n个随机数
再输入一个Q,表示Q个询问
每个询问输入一个a

Output

每个询问输出有多少个区间的gcd不为a

Sample Input

1

5

1 2 4 4 1

4

1

2

3

4

Sample Output

6

12

15

12

题解:考虑到如果固定区间左端点L,那么右端点从L+1变化到n的过程中gcd最多变化logn次(因为每次变化至少除以2),那么我们就可以枚举左端点,然后每次二分值连续的区间,然后都存到map里,只需要将所有的区间个数减去区间gcd=x的个数就是本题的答案

代码:#include<iostream>

#include<cstdio>

#include<cmath>

#include<string>

#include<queue>

#include<algorithm>

#include<stack>

#include<cstring>

#include<vector>

#include<list>

#include<bitset>

#include<set>

#include<map>

using namespace std;

#define LL long long

#define pi (4*atan(1.0))

#define eps 1e-8

#define bug(x)  cout<<“bug”<<x<<endl;

const int N=1e3+10,M=7e6+10,inf=1e9+10,MOD=10;

const LL INF=1e18+10;

 

int a[N];

map<int,LL>dp[N],ans;

map<int,LL>::iterator it;

int main()

{

    int n,T;

    scanf(“%d”,&T);

    while(T–)

    {

        scanf(“%d”,&n);

        ans.clear();

        for(int i=1;i<=n;i++)

            dp[i].clear();

        for(int i=1;i<=n;i++)

            scanf(“%d”,&a[i]);

        for(int i=1;i<=n;i++)

        {

            dp[i][a[i]]++;

            ans[a[i]]++;

            for(it=dp[i-1].begin();it!=dp[i-1].end();it++)

            {

                int x=it->first;

                LL z=it->second;

                int now=__gcd(x,a[i]);

                dp[i][now]+=z;

                ans[now]+=z;

            }

        }

        LL sum=1LL*n*(n+1)/2;

        int q;

        scanf(“%d”,&q);

        while(q–)

        {

            int x;

            scanf(“%d”,&x);

            printf(“%lldn”,sum-ans[x]);

        }

    }

    return 0;

}

1010

QAQ

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K
(Java/Other)

Total Submission(s) : 1082   Accepted Submission(s) : 223

Font: Times New Roman | Verdana | Georgia

Font Size: ← →

Problem Description

定义操作:将数 n 变为 f(n) =
floor(sqrt(n))。即对一个数开平方后,再向下取整。
如对 2 进行一次操作,开平方再向下取整, 1.414213562….. = 1 , 即变为了 1

现在给出一个数 n,如果能在 5 次操作内把 n 变为
1,则输出操作次数;如果则超过5次输出”QAQ”。
数据范围:
1<= n <= 10^100

Input

多组输入,每行输入一个数 n。

Output

每组数据输出要多少次操作,或者输出”QAQ”

Sample Input

233

233333333333333333333333333333333333333333333333333333333

Sample Output

3

QAQ

 

解题报告:签到题,大数

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include<string.h>
using namespace std;

int main()
{
char str[1000005];
 long long n;
 while(cin>>str)
 {  
    double ant=0;
    
  int len=strlen(str);
  if(len>10)
  cout<<“QAQ”<<endl;
  else
  {
  for(int i=0;i<len;i++)
  {
  ant=ant*10+str[i]-‘0’;
 }
 int flag=0;
 while(ant!=1)
 {
  ant= floor(sqrt(ant));
  flag++;
 }
 if(flag>5)
 cout<<“QAQ”<<endl;
 else
 cout<<flag<<endl;
 }
 }
 
    return 0;
}

样例输入:

输出:
82

 5 3

【输入输出样例l解释】
第1次:第1行取行首元素,第2行取行尾元素,本次得分为1*21+2*21=6
第2次:两行均取行首元素,本次得分为2*22+3*22=20
第3次:得分为3*2^3+4*2^3=56。总得分为6+20+56=82

 23 8 91 56 4

【输入输出样例2】

样例输出:

输入:
1 4
4 5 0 5

 23

输出:
122

#include<iostream>

【输入输出样例3】

using
namespace std;

输入:
2 10
96 56 54 46 86 12 23 88 80 43
16 95 18 29 30 53 88 83 64 67

int
a[20001],k;

输出:
316994

 

【限制】
60%的数据满足:1<=n,m<=30,答案不超过10^16
100%的数据满足:l<=n,m<=80,0<=aij<=1000

int
search(int le,int ri)

【分析】

{

这道题的最优子结构性质&子问题重叠都非常明显,很容易写出区间动规的状态转移方程:

    if(le==ri)return a[le];

FL,i,j =
max{(FL,i-1,j + 2x*aL,i-1),
(FL,i,j+1+2x*aL,j+1)}

    int
i=le,j=ri,mid=(i+j)/2,kk=a[mid];

 

   

 证明比较简单,这里不作为讨论重点。。。
再来看数据范围:m最大可达80,ai,j最大可达1000,明显超过了int64的范围(听Pascal党说还有
int128这种数据类型?),我们c++没办法,只好高精度压位。。考虑到“乘法”中只有“高精度*int”这里可以把乘法无耻地改成倍增→_→排除了
乘法,压位的时候不妨多压几位节约资源(实测结果:压8位高精耗时314ms)

    a[mid]=a[le];

 

    while(i<j)

 

    {

www.9778.com 1www.9778.com 2

     
while(i<j&&a[j]>=kk)j–;

 1 #include <cstdio>
 2 #define MOD 100000000
 3 using namespace std;
 4 int M[81][81]={0}, n, m;
 5 struct big
 6 {
 7     int num[5], len;
 8     big() { len = 1;num[0]=0; }
 9     big(int k) {
10         len = 1, num[0]=k % MOD, k/=MOD;
11         while(k)
12             num[len++] = k % MOD, k /= MOD;
13     }
14     big& operator+=(const big& b) {
15         int m=0,i;
16         for(i=0;i<len || i<b.len || m;++i) {
17             if(i<len) m += num[i];
18             if(i<b.len) m += b.num[i];
19             num[i] = m % MOD;
20             m /= MOD;
21         }
22         if(i > len)len = i;
23         return *this;
24     }
25     big operator +(const big& b) {
26         big ans = *this;ans += b;
27         return ans;
28     }
29     big operator *(int b)const {
30         big ans = 0,k = *this;
31         while(b) {
32             if(b&1)ans += k;
33             k += k;
34             b >>= 1;
35         }
36         return ans;
37     }
38     bool operator >(const big& b)const {
39         if(len!=b.len)return len > b.len;
40         int i = len;
41         while(–i>=0)
42             if(num[i]!=b.num[i])return num[i] > b.num[i];
43         return 0;
44     }
45 }s[81][81];
46 int main()
47 {
48     int i,j,t;
49     scanf(“%d%d”,&n,&m);
50     big Ans, po2[81]={1};
51     for(i=1;i<=m;++i)
52         po2[i] = po2[i-1]*2;
53     for(i=0;i<n;++i)
54         for(j=0;j<m;++j)
55             scanf(“%d”,M[i]+j);
56     for(t=0;t<n;++t) {
57         big temp,ans;
58         s[0][m] = 0;
59         for(j = m-1;j>=0;–j)
60             s[0][j] = s[0][j+1] + po2[m-j] * M[t][j];
61         ans = s[0][0];
62         for(i = 1;i <= m;++i)
63             s[i][m] = s[i-1][m] + po2[i] * M[t][i-1];
64         if(s[m][m] > ans)ans = s[m][m];
65         for(i = 1;i < m;++i) {
66             for(j = m-1;j>=i;–j) {
67                 if(s[i-1][j]+po2[m+i-j]*M[t][i-1] > s[i][j+1]+po2[m+i-j]*M[t][j])
68                     s[i][j] = s[i-1][j]+po2[m+i-j]*M[t][i-1];
69                 else s[i][j] = s[i][j+1]+po2[m+i-j]*M[t][j];
70             }
71             if(s[i][i] > ans)ans = s[i][i];
72         }
73         Ans += ans;
74     }
75     i = Ans.len;
76     printf(“%d”,Ans.num[–i]);
77     while(i)
78         printf(“%08d”,Ans.num[–i]);
79     return 0;
80 }

      a[i]=a[j];

动态规划 + 高精度

     
while(i<j&&a[i]<=kk)i++;

      a[j]=a[i];

    }

    a[i]=kk;

    if(i==k)return kk;

    if(k<=i-1)return
search(le,i-1);

    else return search(i+1,ri);

}

int
main()

{

   

   int n;

   n=0; 

   while(1)

   {

     scanf(“%d”,&a[++n]);

     if(a[n]<0)break;

   

   }

    cin>>k;

    cout<<search(1,n-1);

 

}