暑假解题报告

类别集训中集训后总计
Codeforces9312
挑战20525
多校213
合计31940

CF篇
1)Educational Codeforces Round 15, problem: (C) Cellular Network

题意:
几个城市,几个塔,在一条直线上,已知他们的坐标,每个城市至少在R这一范围内有一座塔的信号,求R得最小值
题解:
比较坑,自己YY的二指针,比赛的时候没有搞出来,颇为尴尬。几次遇到int爆数据的问题,以后记得改啊,没事别用int啊。
思路就是求每个城市到塔的最近距离求最大值,由于是不减数列,所以从第一个城市开始,找到离它最近的塔,那么之后的城市的最近的塔只会在后面出现,于是简化了复杂度。
注意当到第一个塔和第二个塔距离相等时候直接下一步,这个时候记录的话会错,

10 10
1 1 2 2 2 4 4 6 7 9
0 1 3 3 3 6 7 8 9 10

比如这样的数据,要是相等就记录下来,哈哈哈哈,你就跑不出333这个序列啦,是不是一脸嘲笑的数据而你移动指针,这时候到第一个塔的值更新了,并不会丢失数据

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
#define pr(x) cout<<#x<<" "<<x;
#define pl(x) cout<<#x<<" "<<x<<endl;
#include<math.h>
#include<algorithm>
#include<set>
#include<map>
#include <queue>
#include<string>
using namespace std;
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    long long city[100005];
    long long tower[100005];
    memset(city,0,sizeof(city));
    memset(tower,0,sizeof(tower));
    for(int i = 0;i<n;i++){
        scanf("%lld",&city[i]);
    }
    for(int i = 0;i<m;i++){
        scanf("%lld",&tower[i]);
    }
    int step =0;
    int num = 0;
    int ans[100005];
    for(int i = 0;i<n;i++){
        for(int  j =step;j<m;){
                long long a = abs( city[i]-tower[j]);
                long long b = 0x7f7f7f7f;
                if(j==m-1){
                    b = 0x7f7f7f7f;
                }
                else{
                    b = abs( city[i]-tower[j+1]);
                }


            if(a>=b){j++;step++;}
            else{
                ans[num] = a;
                num++;
                break;
            }
        }
    }
    int anss=-1;
    for(int i = 0;i<num;i++){
        if(ans[i]>anss){anss=ans[i];}
    }
    printf("%d\n",anss);
}

2)Codeforces Round #363 (Div. 2), problem: (B)

题意:一个炸弹,可以消灭横竖所有墙,问是否能用一个boom消灭地图上所有墙

题解:好吧,这个有点技巧,做法是计算每一列的墙数,存在sl[],计算每一排墙数,存在sh[]中。遍历每一个点,当这个点对应的sl[i]和sh[j]之和减去(这个点是否是墙)==墙数时,则这个点成立。

(if(sh[i]+sl[j]-(maze[i][j]==’*’)==num))

#include<iostream>
#include<sstream>
#include<string>
#include<cstdlib>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cctype>
#include<set>
#include<bitset>
#include<algorithm>
#include<list>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<ctype.h>
#include<time.h>
#define pr(x) cout<<#x<<"  "<<x;
#define pl(x) cout<<#x<<"  "<<x<<endl;
using namespace std;
int sh[1002];
int sl[1002];
int num = 0;
char maze[1005][1005];
int main(){
    int n,m;
    scanf("%d %d",&n,&m);
    getchar();
    memset(sh,0,sizeof(sh));
    memset(sl,0,sizeof(sl));
    for(int i = 1;i<=n;i++){

        for(int j = 1;j<=m+1;j++){
            scanf("%c",&maze[i][j]);
            if(maze[i][j]=='*'){
                num++;
                sh[i]++;
                sl[j]++;
            }
        }

    }
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=m;j++){
            if(sh[i]+sl[j]-(maze[i][j]=='*')==num){
                cout<<"YES"<<endl;
                cout<<i<<" "<<j<<endl;
                return 0;
            }

        }
    }
    cout<<"NO"<<endl;


}

3)Codeforces Round #363 (Div. 2), problem: (C)
题意:一个人每天按照情况可以选择做事或者休息,但是他连续两天不做同一件事,这天能不能做某件事是受条件限制的,求休息的最短天数

题解:
dp,对于每一天的条件下的休息时间的变化是根据以前的来增长的。dp[105][3],列数用来表示每一天,行数0,1,2表示这天在0,1,2这三种情况对这一天的影响。
如果这一天是1,那么你只能选择做1或者休息,那么
dp[i][1] = min(dp[i-1][0],dp[i-1][2]);
而对于今天是0的dp[i][0]来说,没有影响,依旧是
dp[i][0] = 1 + min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]));
不存在做2 的情况,所以dp[i][2]是一种无穷大的情况。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
#define pr(x) cout << #x << ": " << x << "  "
#define pl(x) cout << #x << ": " << x << endl;
#define pri(a) printf("%d\n",(a))
#define xx first
#define yy second
#define sa(n) scanf("%d", &(n))
#define sal(n) scanf("%lld", &(n))
#define sai(n) scanf("%I64d", &(n))
#define vep(c) for(decltype((c).begin() ) it = (c).begin(); it != (c).end(); it++)
const int INF = 0x3f3f3f3f;
int dp[105][3];
int main(){
        int n;
        cin>>n;
        memset(dp,0x3f,sizeof(dp));
        int op;
        dp[0][0] = 0;
            for(int i = 1;i<=n;i++){
                cin>>op;
                if(op == 0){
                    dp[i][0] = 1 + min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]));
                }
                if(op == 1){
                    dp[i][1] = min(dp[i-1][0],dp[i-1][2]);
                    dp[i][0] = 1 + min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]));
                }
                if(op == 2){
                    dp[i][2] = min(dp[i-1][0],dp[i-1][1]);
                    dp[i][0] = 1 + min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]));
                }
                if(op == 3){
                    dp[i][0] = 1 + min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]));
                    dp[i][1] = min(dp[i-1][0],dp[i-1][2]);
                    dp[i][2] = min(dp[i-1][0],dp[i-1][1]);
                }
            }


        int ans = INF;
        ans = min(dp[n][0],min(dp[n][1],dp[n][2]));
        cout<<ans<<endl;


}

4)Codeforces Round #364 (Div. 2), problem: (B) Cells Not Under Attack
题意:
给你一个地图。在其中安放炮塔。炮台可以打到与它同行同列的所有地方,求每一次安放一个炮台,剩余多少地方打不到

题解:
每一次认为是减少了矩形的长和宽,对于安放的地方已有同行的炮台,则只是矩形长减一,对于安放的地方已有同列的炮台,则只是矩形宽减一。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
typedef pair<int, int> p;
typedef long long ll;
typedef unsigned long long ull;
#define pr(x) cout << #x << ": " << x << "  "
#define pl(x) cout << #x << ": " << x << endl;
#define pri(a) printf("%d\n",(a))
#define xx first
#define yy second
#define sa(n) scanf("%d", &(n))
#define sal(n) scanf("%lld", &(n))
#define sai(n) scanf("%I64d", &(n))
#define vep(c) for(decltype((c).begin() ) it = (c).begin(); it != (c).end(); it++)

int main(){
    int n,num;
    cin>>n>>num;

    bool h[n+5];
    bool l[n+5];
    long long step = 1;
    long long nx=n; long long ny=n;
    long long ans[num+5];
    memset(h,false,sizeof(h));
    memset(l,false,sizeof(l));
    int x;int y;

    while(cin>>x>>y){

        if(l[y]==false){
          l[y]=true;
            ny--;
        }
        if(h[x]==false){
          h[x]=true;
            nx--;
        }

        long long a = nx*ny;
        ans[step] = a;
        step++;


    }

    for(int i=1;i<=num;i++){
        cout<<ans[i]<<" ";
    }
    return 0;
}

5)Codeforces Round #364 (Div. 2), problem: (D) As Fast As Possible
题意:
一群人去一个地方,只有一辆车,已知人的速度,路程,车的速度,人数和每一次车的最大载客量,且每个人只能坐一次车。求最短到达时间。
题解:
人的行程分为走路和坐车,当且仅当走路的人和最后一批坐车的人同时到达时,时间最短,按照对称性,可以知道每一批人坐车和走路的时间都是一样的,所以最后是推公式得到坐车和走路的时间。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
#include <string>
#include <string.h>
using namespace std;
typedef pair<int, int> p;
typedef long long ll;
typedef unsigned long long ull;
#define pr(x) cout << #x << ": " << x << "  "
#define pl(x) cout << #x << ": " << x << endl;
#define pri(a) printf("%d\n",(a))
#define xx first
#define yy second
#define sa(n) scanf("%d", &(n))
#define sal(n) scanf("%lld", &(n))
#define sai(n) scanf("%I64d", &(n))
#define vep(c) for(decltype((c).begin() ) it = (c).begin(); it != (c).end(); it++)

int main(){
   int n,k;
   double l,v1,v2;
   cin>>n>>l>>v1>>v2>>k;
   int step;
   if(n%k==0){step = n/k;}
   else{step = n/k+1;}
   double a=(v1+v2)*l/(v1+v2+2*(step-1)*v1);
   double ans = a/v2+(l-a)/v1;
   printf("%.10f\n",ans);
}

6)Educational Codeforces Round 15, problem: (B) Powers of Two
题意:
求两个数加起来是2的次方,这样的数对在数列中有多少组
题解:
爆搜直接over,做出来都有鬼,比较坑的是自己YY的log发生了莫名的错误,卡在第一组很久,颇为尴尬,正解是map,键值是数值,实值是该键值在数列中对应的个数,遍历直到2的32次方然后记录即可

for(int  i =1;i<32;i++){
    ans+= mp[(1<<i)-x];
}
  mp[x]++;
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
#define pr(x) cout<<#x<<" "<<x;
#define pl(x) cout<<#x<<" "<<x<<endl;
#include<math.h>
#include<algorithm>
#include<set>
#include<map>
#include <queue>
#include<string>
#include<cmath>
using namespace std;
map <int ,int > mp;
int main(){
    int n;
    scanf("%d",&n);
    int num[100005];
    long long ans = 0;
    for(int  i = 0;i<n;i++){
        int x;scanf("%d",&x);
        for(int  i =1;i<32;i++){
            ans+= mp[(1<<i)-x];
        }
        mp[x]++;
    }
    printf("%I64d",ans);
}

7)CF Educational Round 12, B
题意:
给你一组数字(从1到n,乱序),每次让你找到某一个数字,记录下它的位置i,然后将i加到ans上,然后将这个数字提到队首,于是在新的数字排序中找下一个数,最后输出ans
题解:
模拟整个过程,暴力解法,注意每次初始化小数组储存用户的order

#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;
int main(){
    int str[103];
    int numofcus;
    int numoforder;
    int numofitem;
    int ans=0;
    cin>>numofcus>>numoforder>>numofitem;
    for(int i=1;i<=numofitem;i++){cin>>str[i];}
    int turn=numofcus;
    while(turn){
        int cusorder[numoforder];
        memset(cusorder,0,sizeof(cusorder));
        for(int i=0;i<numoforder;i++){
            cin>>cusorder[i];
        }
        for(int i=0;i<numoforder;i++){
            for(int j=1;j<=numofitem;j++){
                if(cusorder[i]==str[j]){
                    ans+=j;
                   int temp=str[j];
                   for(int k=j;k>1;k--){//重组数组
                    str[k]=str[k-1];
                   }
                    str[1]=temp;
                    j=1;
                    break;

                }

            }

        }

        turn--;

    }

cout<<ans<<endl;
}

8)Codeforces Round #363 (Div. 2), problem: (C)
题意:一个人每天按照情况可以选择做事或者休息,但是他连续两天不做同一件事,这天能不能做某件事是受条件限制的,求休息的最短天数

题解:
dp,对于每一天的条件下的休息时间的变化是根据以前的来增长的。dp[105][3],列数用来表示每一天,行数0,1,2表示这天在0,1,2这三种情况对这一天的影响。
如果这一天是1,那么你只能选择做1或者休息,那么
dp[i][1] = min(dp[i-1][0],dp[i-1][2]);
而对于今天是0的dp[i][0]来说,没有影响,依旧是
dp[i][0] = 1 + min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]));
不存在做2 的情况,所以dp[i][2]是一种无穷大的情况。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
#define pr(x) cout << #x << ": " << x << "  "
#define pl(x) cout << #x << ": " << x << endl;
#define pri(a) printf("%d\n",(a))
#define xx first
#define yy second
#define sa(n) scanf("%d", &(n))
#define sal(n) scanf("%lld", &(n))
#define sai(n) scanf("%I64d", &(n))
#define vep(c) for(decltype((c).begin() ) it = (c).begin(); it != (c).end(); it++)
const int INF = 0x3f3f3f3f;
int dp[105][3];
int main(){
        int n;
        cin>>n;
        memset(dp,0x3f,sizeof(dp));
        int op;
        dp[0][0] = 0;
            for(int i = 1;i<=n;i++){
                cin>>op;
                if(op == 0){
                    dp[i][0] = 1 + min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]));
                }
                if(op == 1){
                    dp[i][1] = min(dp[i-1][0],dp[i-1][2]);
                    dp[i][0] = 1 + min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]));
                }
                if(op == 2){
                    dp[i][2] = min(dp[i-1][0],dp[i-1][1]);
                    dp[i][0] = 1 + min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]));
                }
                if(op == 3){
                    dp[i][0] = 1 + min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]));
                    dp[i][1] = min(dp[i-1][0],dp[i-1][2]);
                    dp[i][2] = min(dp[i-1][0],dp[i-1][1]);
                }
            }


        int ans = INF;
        ans = min(dp[n][0],min(dp[n][1],dp[n][2]));
        cout<<ans<<endl;


}

9)Codeforces Round #201 (Div. 2)C——数论
题意:
A 和 B玩游戏,A每次先手,游戏规则:在一个集合中找到两个数,他们的差绝对值不在集合中,则添加到集合里。如果无法选择了,那个人就是输了。
题解:
模拟不可能,这题找规律。
好吧,证明下面的结论也是无力。
所有初始数的最大公约数gcd,集合={1*gcd,2*gcd,…k*gcd≤max}max=⁡所有初始数的最大值。

int gcd(int a, int b) {  
    if(b == 0)  
        return a;  
    return gcd(b, a % b);  
}

这里贴一下gcd代码,自己写的就是垃圾。。。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
int gcd(int x,int y){
    if(x<y)
    swap(x,y);
    if(x%y==0){return y;}
    else {
    int temp=x;
    x=y;
    y=temp%y;
    return gcd(x,y);
    }

}
int main(){
int n;
cin>>n;
int num[105];
int maxn=-1;
for(int i=1;i<=n;i++){
    cin>>num[i];
    if(num[i]>maxn){maxn=num[i];}
}
int temp= gcd(num[1],num[2]);
for(int i=3;i<=n;i++){
   temp=gcd(temp,num[i]);
}
if((maxn/temp-n)%2==0)cout<<"Bob"<<endl;
else cout<<"Alice"<<endl;
}

总结:第一次接触数论的题,这种“guess+几种样例观察结果”的方法,或许是一种可行的解法。。。
10)CF Educational Round 12, C
题意:
给一个字符串,要求通过最少的改变(每次只能改变一个字符)将其变成两两之间互不相等的字符串(有多种结果,只需要输出其中一种)
题解:
我的思路:首先两两比较,若相等,则将后面一个变换。使得变换后的字符不等于他的下一个字符(即aab->acb,而不是aab->abb)[好吧,自己在写的时候坑了自己,就是我是使用直接加减来改变,坑自己的点在y上(如果y后面是z,那么我的代码就使得y+了2.。。。于是就超出了范围。。。泪崩。。好吧,我还是觉得使用round比较好,,判断一下重来就行了)]

#include<iostream>
#include<string>
#include<stdio.h>
using namespace std;
int main(){
string s;
cin>>s;
for(int i=1;i<s.size();){
    if(i==s.size()-1)
    {
        if(s[i-1]==s[i])
        {
            if(s[i]=='z'){s[i]-=1;}
            else if(s[i]=='a'){s[i]+=1;}
            else{s[i]+=1;}
        }
        break;
    }
    if(s[i]==s[i-1]){
        if(s[i]=='z')
        {
            s[i]-=1;
            if(s[i+1]==s[i])
            {s[i]-=1;}

        }
        else if(s[i]=='a')
        {
            s[i]+=1;
            if(s[i+1]==s[i])
            {s[i]+=1;}

        }
        else
 {
            s[i]+=1;
            if(s[i+1]==s[i])
            {s[i]+=1;if(s[i]>'z')s[i]-=3;}

        }
        i+=2;continue;
    }
i++;
}
cout<<s<<endl;
return 0;
}

11)Codeforces Round #348,D
题意:
给你一组数1~n,有三种转换方式。一,左旋转。二,右旋转。三,位置1和位置2互换;位置3和位置4互换,以此类推。最后输出这组数据。
题解:
我的思路:1.q1[],q2[]储存变换方式的数据,2.旋转方式使用函数change(这是一个旋转的写法:首先,旋转可以看做是两段数据之间的变换,具体方式:两段数据分别做反转,再将整体做反转。例如:1234->12 34->21 43->3412,这样就实现了左旋转2位)3.互换,使用swap解决。
PS:最后这个方法失败了。当测试很大的数据的时候就time limit。。。估计是旋转方式需要对每一个数数据处理,太复杂。
AC方法:实际上,我们只需要确定1,2的位置就能找到整组数的排列方式,所以,所有的工作就是对于初始位于位置1,2的数字1,2的变换。
通过判断是否出现倒回(即从头一步之后到尾;从尾一步之后到头)分成两种情况
在有倒回的这种情况中,根据我的方法实际有效的移动的步数是q2[i]%n,这就出现了如果刚好回到原始点(即q2[i]%n==0)便不再实用我推的公式(这个就是自己被坑,调了好久才知道的地方),所以此情况再分成2种。

/*#include<iostream>
#include<cstdio>
using namespace std;
void change(int *arr,int head,int bottem){
for(;head<bottem;head++,bottem--){
    int temp;
    temp=arr[head];
    arr[head]=arr[bottem];
    arr[bottem]=temp;

}
}

int main(){
int n;
int q;
cin>>n>>q;
int num[n+5];
int q1[q+5];
int q2[q+5];
for(int i=1;i<=q;i++){
scanf("%d",&q1[i]);
if(q1[i]==1){scanf("%d",&q2[i]);}

}
for(int i=1;i<=n;i++){
    num[i]=i;
}
for(int i=1;i<=q;i++){
    if(q1[i]==1){
        if(q2[i]>=0){
            //向右移动
            change(num,1,n-q2[i]);
            change(num,n-q2[i]+1,n);
            change(num,1,n);
        }
       if(q2[i]<0){
        //向左移动
        change(num,1,-q2[i]);
        change(num,-q2[i]+1,n);
        change(num,1,n);
       }
    }
    else {//交换
        for(int i=1;i<=n;){
            swap(num[i],num[i+1]);
            i+=2;

        }
    }

}
for(int i=1;i<=n;i++){
    printf("%d ",num[i]);

}

}
*/
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
int n;
int q;
cin>>n>>q;
int num[n+5];
int q1[q+5];
int q2[q+5];
for(int i=1;i<=q;i++){
scanf("%d",&q1[i]);
if(q1[i]==1){scanf("%d",&q2[i]);}

}
int index1=1;
int index2=2;
for(int i=1;i<=q;i++){
    if(q1[i]==1){
        if(q2[i]>=0){
            if(index1+q2[i]<=n){index1+=q2[i];}
            else {
                if(q2[i]%n==0){;}
                else{index1=index1+(q2[i]%n)-n;}

            }
            if(index2+q2[i]<=n){index2+=q2[i];}
            else {
                if(q2[i]%n==0){;}
                else {index2=index2+(q2[i]%n)-n;}
            }
        }
        if(q2[i]<0){
            if(index2+q2[i]>=1){index2=q2[i]+index2;}
            else {
                if(-q2[i]%n==0){;}
                else {index2=index2+n+(q2[i]%n);}
            }
            if(index1+q2[i]>=1){index1=q2[i]+index1;}
            else {
                if(-q2[i]%n==0){;}
                else {index1=index1+n+(q2[i]%n);}
            }
        }
    }
    else{
        if(index1%2==0){index1-=1;}
        else{index1+=1;}
        if(index2%2==0){index2-=1;}
        else{index2+=1;}
    }

}
num[index1]=1;
num[index2]=2;
for(int i=index1+2,j=index2+2,k=1;k<n/2;k++){
    if(i>n)i-=n;
    if(j>n)j-=n;
    num[i]=2*k+1;
    num[j]=2*k+2;
    i+=2;
    j+=2;
}
for(int i=1;i<=n;i++){
    printf("%d ",num[i]);

}

}

12)Codeforces Round #348,C
题意:
有一个矩阵(N*M),经过若干种变化,行旋转,列旋转,赋值。得到最终的矩阵。求初始矩阵是多少。
题解:
1.用数组来储存每一组数据(这里使用scanf来输入,特别是数据每种情况下数量不同,需要判断)
2.从最后一组数据开始,暴力向上一步一步模拟(好吧,这里吐槽一下我自己在写代码的时候使用了0行0列,写的时候巨烦。。。。)
3.所谓的旋转,例如行左旋转,就是temp=末尾,然后从倒数第二个开始,前一次向后赋值,最后首个数据=temp,这是最简单的方法
4. 注意输出时:%d后的空格,以及一行输出后的换行。(注意格式)

for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            printf("%d ",matrix[i][j]);
        }
        cout<<endl;
}
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
int main(){
int n;
int m;
int op;
cin>>n>>m>>op;
int matrix[n][m];
memset(matrix,0,sizeof(matrix));
int t[10100],r[10100],c[10100],x[10100];

for(int i=0;i<op;i++){
        scanf("%d",&t[i]);
        if(t[i]==1) scanf("%d",&r[i]);
        else if(t[i]==2) scanf("%d",&c[i]);
        else scanf("%d%d%d",&r[i],&c[i],&x[i]);
    }
for(int i=op-1;i>=0;i--){
    if(t[i]==3)
    {
    matrix[r[i]-1][c[i]-1]=x[i];
    }
    else if(t[i]==2) {
    int temp;
    temp=matrix[n-1][c[i]-1];
    for(int j=n-1;j>0;j--){
        matrix[j][c[i]-1]=matrix[j-1][c[i]-1];
    }
    matrix[0][c[i]-1]=temp;
    }//changecolumn(matrix,c[i]);
    else {
    int temp;
    temp=matrix[r[i]-1][m-1];
    for(int j=m-1;j>0;j--){
        matrix[r[i]-1][j]=matrix[r[i]-1][j-1];
    }
    matrix[r[i]-1][0]=temp;


    }//changerow(matrix,r[i]);
}
for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            printf("%d ",matrix[i][j]);
        }
        cout<<endl;
}

}


挑战篇
1.DFS
1)Poj 1979
题意:一个地图,求从起点开始,可以到达的点的个数,其中有墙阻隔,默认有边界。

题解:DFS,从起点开始,先替换这个点使之成为墙,然后四个方向进行搜索,知道没有点为止。

注意:在输入地图时,应该注意加一个为止存放’\n’,所以第二层for要+1宽度;还有在输入地图规格时候注意加上getchar,以免后面混乱
(当输入的是数字地图时候,不需要加宽)

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define pr(x) cout<<#x<<" "<<x;
#define pl(x) cout<<#x<<" "<<x<<endl;
using namespace std;
char maze[30][30];
int ans=0;
int dx[] = {0,0,-1,1};
int dy[] = {-1,1,0,0};
int H,L;
void dfs(int x,int y){
    maze[x][y]='#';
    ans++;
    for(int i = 0; i<4; i++){
        int nx = x + dx[i];
        int ny = y + dy[i];
    //    pl(maze[nx][ny]);
        if(nx<L&&nx>=0&&ny<H&&ny>=0&&maze[nx][ny]=='.')
            {
                dfs(nx,ny);
            }
    }

}

int main(){
    while(1){
       int x,y;
       scanf("%d %d",&L,&H);
       getchar();
       if(H==0){return 0;}
       for(int i = 0; i<H; i++){
        for(int j = 0; j<L+1; j++){
            scanf("%c",&maze[j][i]);
            if(maze[j][i]=='@'){
                x=j;
                y=i;
            }
        }
       }
       dfs(x,y);
       printf("%d\n",ans);
       ans=0;

    }

}

2)Poj 3009
题意:
地图上有起点和终点,你每次向四个方向移动冰球,知道它撞到障碍位置,且此时此障碍消失。注意:你必须有扔球的缓冲区域,即四个方向有一个是没有障碍物的,求是否可以到终点一个到终点的最小步数,大于10步就算不能到达,球在运动过程中不能出界。

题解:
1.dfs包含3个参数 x,y,step,每一次for里面只会出现遇到1,遇到3,出界的情况,用是否出界来作为每一次dfs的结束条件while (judge(a, b))
2.if (step > 10) return
;
用来减枝
3.由于有缓冲区间,cflag用来判断是否是有缓冲区间,然后返回到上一个点,进行下一次dfs

 if (grid[a][b] == 1 && cflag > 1) {
  grid[a][b] = 0;
  dfs(a-dir[i][0], b-dir[i][1], step+1);
  grid[a][b] = 1;
  }

其中需要注意的是 grid[a][b] = 1; 这是还原地图,因为你每次完成一次初始第一步之后的所有dfs之后,需要还原这个地图,这句非常重要

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;

const int INFS = 0x3fffffff;
int grid[25][25], row, col, ans;
int dir[4][2] = {-1, 0, 1, 0, 0, -1, 0, 1};

inline bool judge(int x, int y) {
    if (0 < x && x <= row && 0 < y && y <= col) {
        return true;
    }
    return false;
}

void dfs(int x, int y, int step) {
    if (step > 10)
        return ;

    for (int i = 0; i < 4; ++i) {
        int a = x, b = y, cflag = 0;
        while (judge(a, b)) {
            a += dir[i][0];
            b += dir[i][1];
            cflag += 1;

            if (grid[a][b] == 3) {
                ans = min(ans, step + 1);
                return ;
            }
            if (grid[a][b] == 1) 
                break ;
        }
        if (grid[a][b] == 1 && cflag > 1) {
            grid[a][b] = 0;
            dfs(a-dir[i][0], b-dir[i][1], step+1);
            grid[a][b] = 1;
        }
    }
}

int main() {

    while (scanf("%d%d", &col, &row) && col && row) {
        int x, y;
        memset(grid, 0, sizeof(grid));

        for (int i = 1; i <= row; i++) {
            for (int j = 1; j <= col; j++) {
                scanf("%d", &grid[i][j]);
                if (grid[i][j] == 2) 
                    x = i, y = j;
            }
        }

        ans = INFS;
        dfs(x, y, 0);
        if (ans <= 10)
            printf("%d\n", ans);
        else
            printf("-1\n");
    }
}

3)AOJ 0033
题意:有一个数列,1-10,10个元素乱排,问是否可以将数列按顺序抽出元素组成新数列,使得新数列是递增的而且原数列剩下的数字也是递增的
题解:
dfs,记录步数和当前两个新数列的末尾,如果可以放,就下一轮dfs,完全是模拟了题目的一个图形

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
#define pr(x) cout<<#x<<" "<<x;
#define pl(x) cout<<#x<<" "<<x<<endl;
#include<math.h>
#include<algorithm>
using namespace std;
int num[10];
bool dfs(int step,int btop,int ctop){
    if(step==9){
        if(num[step]>btop||num[step]>ctop){
            return true;
        }
        else return false;
    }
    bool b = false;
    bool c = false;
    if(num[step]>btop){b = dfs(step+1,num[step],ctop);}
    if(num[step]>ctop){c = dfs(step+1,btop,num[step]);}

    return (b||c);

}

int main(){
    int t;
    cin>>t;
    while(t--){
      memset(num,0,sizeof(num));
      for(int i = 0;i<10;i++){
        cin>>num[i];
      }
      bool ans = dfs(0,0,0);
      if(ans){cout<<"YES"<<endl;continue;}
      else{cout<<"NO"<<endl;continue;}


    }

}

2.BFS
1)Poj 3669
题意:
有个人去看流星雨,不料流星掉下来会砸毁上下左右中五个点。每个流星掉下的位置和时间都不同,人不能待在流星毁过的地方,人从0,0出发,每次人只能走上下左右中一步,求他是否能求小文青能否到安全的地方,如果能,最短的逃跑时间是多少?

题解:
1.对地图初始化,流星破坏的地方设置成他的下落时间,其他地方设置成INF
2.struct里面记录坐标和时间,每一次的上下左右移动需要判断出界和时间加+1,并且要记录是否来过,从而剪枝,如果走到了地方是INF,那么可以,否则输出-1。

注意:
1.这个题是地图初始化,从而得到成立条件。
2.visited[][]记录每个点是否到达,剪枝
3.结构体里面的参数设置

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
#define pr(x) cout<<#x<<" "<<x;
#define pl(x) cout<<#x<<" "<<x<<endl;
using namespace std;
int maze[305][305];
int dx[] = {0,0,-1,1};
int dy[] = {-1,1,0,0};
bool visited[305][305];
const int INF = 0x3f3f3f3f;
struct p{
    int x,y,time;

};
int bfs(){
    queue<p> que;
    p np;
    np.x=0;np.y=0;np.time=0;
    que.push(np);
    visited[0][0] = true;
    if(maze[0][0]==INF){return 0;}
    if(maze[0][0]==0){return -1;}
    while(que.size()){

        p cp = que.front();
        que.pop();
        for(int i = 0;i < 4;i++){
            np = cp;
            np.x = np.x + dx[i];
            np.y = np.y + dy[i];
            np.time = np.time+1;
                if(np.time<maze[np.x][np.y]&&!visited[np.x][np.y]&&np.x>=0&&np.y>=0){
                if(maze[np.x][np.y]==INF){return np.time;}
                  que.push(np);
                  visited[np.x][np.y] = true;
                }
        }


    }
    return -1;

}
int main(){
    int n;
    scanf("%d",&n);
    int a,b,t;
    for(int i = 0;i<305;i++){
        for(int j = 0;j<305;j++){
            maze[i][j] = INF;
            visited[i][j] = false;
        }
    }
    while(n--){
        scanf("%d %d %d",&a,&b,&t);
        maze[a][b] = min(maze[a][b],t);
            for(int j = 0; j<4 ;j++){
                    if((a+dx[j])>=0&&(b+dy[j])>=0)
                   {
                       maze[a+dx[j]][b+dy[j]] = min(maze[a+dx[j]][b+dy[j]],t);
                   }
            }


    }



    int ans = bfs();
    printf("%d\n",ans);

}

2)AOJ 0558
题意:
一个地图,需要先从起点到1再到2,,,,以此类推,问最短路程
题解:
明显最短路程就是bfs,每一次把起点和目的地换了,多次bfs
注意:输入地图时,可以使用如下方法,避免每一个字符输入时对‘\n’还要处理

    cin>>h>>w>>n;
    getchar();
    for(int i = 0;i<h;i++){
        scanf("%s",&maze[i]);
    }
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
#define pr(x) cout<<#x<<" "<<x;
#define pl(x) cout<<#x<<" "<<x<<endl;
#include<math.h>
#include<algorithm>
using namespace std;
char maze[1005][1005];
int dx[] = {-1,1,0,0};
int dy[] = {0,0,-1,1};
int d[1005][1005];
const int INF = 0x7f7f7f7f;
typedef pair <int ,int > p;
queue <p> que;
int h,w;
void chushihua(){
    for(int i = 0;i<1005;i++){
        for(int j = 0;j<1005;j++){
            d[i][j] = INF;
        }
    }
}
int bfs(int x,int y,int gx,int gy){
    chushihua();
    d[x][y] = 0;
    que.push(p(x,y));
    while(que.size()){
        p cp = que.front();
        que.pop();
        if(cp.first==gx&&cp.second==gy){break;}
        for(int i = 0;i<4;i++){
            int nx = cp.first + dx[i];
            int ny = cp.second + dy[i];
            if(nx>=0&&nx<h&&ny>=0&&ny<w&&maze[nx][ny]!='X'&&d[nx][ny]==INF){

               que.push(p(nx,ny));
               d[nx][ny] = d[cp.first][cp.second] + 1;

            }
        }
    }
    while(que.size()){que.pop();}
    return d[gx][gy];


}
int main(){
    int n;
    cin>>h>>w>>n;
    int indexmap[n+5][4];
    getchar();
    for(int i = 0;i<h;i++){
        scanf("%s",&maze[i]);
    }
    for(int i = 0;i<h;i++){
        for(int j = 0;j<w;j++){
            if(maze[i][j]=='S'){
                indexmap[0][0] = i;
                indexmap[0][1] = j;

            }
            else if((int)maze[i][j]>=49&&(int)maze[i][j]<=57){
                int index = maze[i][j]-'0';
                indexmap[index][0] = i;
                indexmap[index][1] = j;


            }
        }
    }
    int ans = 0;
    for(int i=0;i<n;i++){
        ans += bfs(indexmap[i][0],indexmap[i][1],indexmap[i+1][0],indexmap[i+1][1]);
    }
    cout<<ans<<endl;

}

3)AOJ 0121
题意:
对于一个4X2的方格,有7个方片对应1–7,一个空格对应0,移动使得方格从左到右从上到下依次是01234567,问最短步数
题解:
使用map,map有两个数,以第一个数作为排序的标准,以第二个数作为该map对应的值

map <string, int> dp;

对于每一次的移动,直接抽象到一行来,注意条件的判断

int direction[4] = { 1, -1, 4, -4 };
int n = index + direction[i];
//index是0的位置,括号分别表示右上角不能右移了和左下角不能左移了
if(n>=0&&n<8&&!(index==3&&i==0)&&!(index==4&&i==1))

注意:对于一行有空格且不知道长度的字符串,去空格的方法

string line;
    while (getline(cin, line))
    {
        line.erase(remove(line.begin(), line.end(), ' '), line.end());
    }
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
#define pr(x) cout<<#x<<" "<<x;
#define pl(x) cout<<#x<<" "<<x<<endl;
#include<math.h>
#include<algorithm>
#include<set>
#include<map>
#include<unordered_set>
using namespace std;
map <string, int> dp;
int direction[4] = { 1, -1, 4, -4 };
void bfs(){
    queue <string >que;
    que.push("01234567");
    dp["01234567"] = 0;
    while(que.size()){
        string now = que.front();
        que.pop();
        int index = 0;
        for(int i = 0;i<8;i++){
            if(now[i] =='0'){
                index = i;
                break;
            }
        }
        for(int i =0;i<4;i++){
            int n = index + direction[i];
            if(n>=0&&n<8&&!(index==3&&i==0)&&!(index==4&&i==1)){
                string next = now;
                swap(next[n],next[index]);
                if(dp.find(next)==dp.end()){
                    dp[next] = dp[now]+1;
                    que.push(next);
                }
            }
        }
    }

}



int main(){
    bfs();
    string line;
    while (getline(cin, line))
    {
        line.erase(remove(line.begin(), line.end(), ' '), line.end());
        cout << dp[line] << endl;
    }

    return 0;


}

3.爆搜
1)AOJ 0525
题意:
一个地图,只有0,1,每次可以转换一行或者一列,使得一行或者一列的0和1值互换,求最多可以有多少个1
题解:
先对行爆搜,以为题中行数少,然后对每一列记录1的个数和0的个数,取较大值,其中使用了bitset简单的实现了转换

bitset <10000> a[10];

对于行的爆搜,使用了二进制转换从0到pow(2,r)-1,每个数的二进制数对应是否转换这一行

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
#define pr(x) cout<<#x<<" "<<x;
#define pl(x) cout<<#x<<" "<<x<<endl;
#include<math.h>
#include<algorithm>
#include<set>
#include<map>
#include<unordered_set>
#include<bitset>
using namespace std;
bitset <10000> a[10];
int str[10];
void change(int x){
    memset(str,0,sizeof(str));
    for(int i = 0;x>0;i++){
        str[i] = x%2;//pl(str[i]);
        x = x/2;
    }


}
int main(){
    int r,c;


    while(cin>>r>>c&&r!=0){
            int ans =0;
        for(int i = 0;i<r;i++){
            for(int j = 0;j<c;j++){
                bool b;
                cin>>b;
                a[i][j] = b;
            }
        }

        for(int i = 0;i<pow(2,r);i++){
        int anss=0;
        change(i);
        for(int j = 0;j<r;j++){
            if(str[j]==1){a[j].flip();}
        }
        for(int k = 0;k<c;k++){
                int ccount =0;
            for(int i =0;i<r;i++){
                if(a[i][k]==1){ccount++;}
            }
            //pl(ccount);
            anss +=max(ccount,r-ccount);
        }
        ans = max(ans,anss);

        for(int j = 0;j<r;j++){
            if(str[j]==1){a[j].flip();}
        }

    }

    cout<<ans<<endl;



    }

}

2)POJ 2718
题意:
对于一个数列,我们将数字分成两堆,求可能的情况下,两堆数字组成的数的差的最小值,排除前导0
题解:
将给出的数列进行字典序排列,然后将每个部分的转化成数字做差比较,因为字典序,所以枚举了所有数字

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
#define pr(x) cout<<#x<<" "<<x;
#define pl(x) cout<<#x<<" "<<x<<endl;
#include<math.h>
#include<algorithm>
#include<set>
#include<map>
#include<bitset>
#include<string>
using namespace std;
int calnum(int str[],int eindex){
    int a= 0;
    for(int i = 0 ;i<eindex;i++){
        a = str[i]+a*10;
    }
    return a;

}
int main(){
    int t;
    cin>>t;
    cin.ignore();
    while(t--){
        string s;
        getline(cin,s);
        s.erase(remove(s.begin(),s.end(),' '),s.end());
        int length = s.size();
        int nums[length];
        for(int i = 0;i<length;i++){
            nums[i] = s[i]-'0';
        }
        int numa[length];
        int numb[length];
        int bendindex;
        int ans=0x7f7f7f7f;
        if(length%2==0){
            bendindex = length/2;
        }
        else{
            bendindex = length/2+1;
        }
        do{
            for(int i = 0;i<length/2;i++){
                numa[i] = nums[i];
            }
            for(int i = length/2,j = 0;i<length;i++,j++){
                numb[j] = nums[i];
            }

            if((numa[0]==0&&length/2>1)||
                (numb[0]==0&&bendindex>1)
                ){continue;}
            else{
                int a = calnum(numa,length/2);
                int b = calnum(numb,bendindex);
                ans = min(ans,abs(a-b));

            }

        }while(next_permutation(nums,nums+length));

        cout<<ans<<endl;
    }

}

3)POJ 3050
题意:从一个起点,走5步,能组成几个六位数
题解:
用set直接排除重复项最easy,爆搜每一个起点

dfs(int x,int y,int step,int s)

if(step==5){
   if(ansset.find(s)==ansset.end()){
         ansset.insert(s);
    }
    return;
}

实际上并不需要判断,因为set不会装重复元素

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
#define pr(x) cout<<#x<<" "<<x;
#define pl(x) cout<<#x<<" "<<x<<endl;
#include<math.h>
#include<algorithm>
#include<set>
#include<map>
#include<bitset>
#include<string>
#include<cstring>
#include<sstream>
using namespace std;
int maze[5][5];
set<int> ansset;
int dx[] = {-1,1,0,0};
int dy[] = {0,0,-1,1};
bool isin(int x,int y){
    if(x>=0&&x<5&&y>=0&&y<5){return true;}
    else{return false;}
}
void dfs(int x,int y,int step,int s){
        if(step==5){
            if(ansset.find(s)==ansset.end()){
                ansset.insert(s);
            }
            return;
        }
        for(int i =0;i<4;i++){
            int nx = x + dx[i];
            int ny = y + dy[i];
            if(isin(nx,ny)){

            dfs(nx,ny,step+1,s*10+ maze[nx][ny]);

            }
        }


}
int main(){
    for(int i = 0;i<5;i++){
        for(int j = 0;j<5;j++){
            cin>>maze[i][j];
        }
    }
    for(int i = 0;i<5;i++){
        for(int j = 0;j<5;j++){

            dfs(i,j,0,maze[i][j]);
        }
    }
    cout<<ansset.size()<<endl;
}

4.贪心
1)POJ 2376
题目:
给定一个时间T和N个时间区间,求最少需要多少个区间覆盖总区间[1,T],无法覆盖区域[1,T]时输出-1。
例如T=10,有3个区间[1,7],[3,6],[6,10],则最少需要两个区间来覆盖,选择区间1和区间3。
题解:
先给区域排序,起始点为1 的开始,遍历得到起始点为1,终点最远的位置,然后判断他是否有更新,没有就输出-1,直到end>=t输出。

bool cmp(cow a,cow b){
    return a.begin<b.begin||(a.begin==b.begin&&a.end<b.end);
}
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
#define pr(x) cout<<#x<<" "<<x;
#define pl(x) cout<<#x<<" "<<x<<endl;
#include<math.h>
#include<algorithm>
#include<set>
#include<map>
#include<bitset>
#include<string>
#include<cstring>
#include<sstream>
using namespace std;
struct cow{
int begin;
int end;
};
cow cowstr[25000];
bool cmp(cow a,cow b){
    return a.begin<b.begin||(a.begin==b.begin&&a.end<b.end);
}
int main(){
    int n,t;
    cin>>n>>t;
    for(int i = 0;i<n;i++){
        cin>>cowstr[i].begin>>cowstr[i].end;
    }
    sort(cowstr,cowstr+n,cmp);
    int ans = 0;
    int end = 0;
    int startindex = 0;
    while(end<t){
        int begin = end +1;
        for(int i =startindex;i<n;i++){
            if(cowstr[i].begin<=begin){
                if(cowstr[i].end>=begin){
                    end = max(end,cowstr[i].end);
                }
            }
            else{
                startindex = i;
                break;
            }
        }
        if(begin>end){cout<<-1<<endl;return 0;}
        else{
            ans++;
        }
    }
    cout<<ans<<endl;
}

2)POJ 1328

题意:假设海岸线是一条无限延伸的直线。每一个小的岛屿是海洋上的一个点。雷达坐落于海岸线上,只能覆盖d距离,所以如果小岛能够被覆盖到的话,它们之间的距离最多为d。

题目要求计算出能够覆盖给出的所有岛屿的最少雷达数目。
这里写图片描述
一目了然,求投影到X轴上,然后重叠位置只记一次,有两种情况:当此时的线段左端点大于此时比较的右端点,不会有重合了,更新;当当此时的线段右端点小于此时比较的右端点,范围更小了,更新比较线段(这样做都是建立在sort之后,每一线段的左端点不减)

#include <iostream>  
#include <algorithm>  
#include <stdlib.h>  
#include <math.h>  

using namespace std;  

struct point  
{  
    double left, right;  
}p[2010], temp;  

bool operator < (point a, point b)  
{  
    return a.left < b.left;  
}  

int main()  
{  
    int n;  
    double r;  
    int kase = 0;  
    while (cin >> n >> r && (n || r))  
    {  
        bool flag = false;  
        for (int i = 0; i < n; i++)  
        {  
            double a, b;  
            cin >> a >> b;  
            if (fabs(b) > r)  
            {  
                flag = true;  
            }  
            else  
            {  
                p[i].left = a * 1.0 - sqrt(r * r - b * b);  
                p[i].right = a * 1.0 + sqrt(r * r - b * b);  
            }  
        }  
        cout << "Case " << ++kase << ": ";  
        if (flag)  
        {  
            cout << -1 << endl;  
        }  
        else  
        {  
            int countt = 1;  
            sort(p, p + n);  
            temp = p[0];  

            for (int i = 1; i < n; i++)  
            {  
                if (p[i].left > temp.right)  
                {  
                    countt++;  
                    temp = p[i];  
                }  
                else if (p[i].right < temp.right)  
                {  
                    temp = p[i];  
                }  
            }  
            cout << countt << endl;  
        }  
    }  
}  

3)POJ 3190
题意:
每一只奶牛要求在时间区间[A,B]内独享一个牛栏。问满足奶牛整个过程最少需要多少个牛栏。
题解:
在优先队列里面设为end最前的先输出,sort以begin的时间从小到大排序。
t数组是记录每一只牛的牛栏编号
如果

c.end < cstr[i].begin

则这个栏的牛的end时间要更新了。
否则加牛栏

#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <math.h>
#include <queue>
using namespace std;
struct cow{
    int begin,end,num;
    friend bool operator <(cow a ,cow b){
    return a.end>b.end;

    }
} cstr[50005];
bool cmp(cow c1,cow c2){

return c1.begin<c2.begin;
}
int t[50005];
int main(){
    int n;
    cin>>n;
    for(int i = 0;i<n;i++){
        cin>>cstr[i].begin>>cstr[i].end;
        cstr[i].num = i;
    }
    int r= 0;
    sort(cstr,cstr+n,cmp);
    priority_queue <cow> q;
    q.push(cstr[0]);
    t[cstr[0].num] = ++r;
    for(int i =1;i<n;i++){
        cow c = q.top();
        if(c.end < cstr[i].begin){
            t[cstr[i].num] = t[c.num];
            q.pop();
            q.push(cstr[i]);
        }
        else{
            t[cstr[i].num] = ++r;
            q.push(cstr[i]);
        }
    }
    cout<<r<<endl;
    for(int i = 0;i<n;i++){
        cout<<t[i]<<endl;
    }

}

4)POJ 2393
题意:
你每周可以生产牛奶,每周生产的价格为Ci,每周需要上交的牛奶量Yi,你可以选择本周生产牛奶,也可选择提前几周生产出存储在仓库中(仓库无限大,而且保质期不考虑),每一周存仓库牛奶需要花费S元,让你求出所有周的需求量上交的最少花费。
题解:
决定你是否提前生产就是看单价,实际上对于每一次的比较只需要比较当前值和以前的最优解,如果比最优解小,那么此时他变成当前最优解。以此类推

#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <math.h>
#include <queue>
using namespace std;
typedef long long ll;
int main(){
    int n,s;
    cin>>n>>s;
    ll cost[10000];
    ll need[10000];
    ll ans = 0;
    for(int i = 0;i<n;i++){
        cin>>cost[i]>>need[i];

    }
    int best = 0;
    for(int i =1;i<n;i++){
        if(cost[i]>=(i-best)*s+cost[best]){
            cost[i] = (i-best)*s+cost[best];
        }
        else{
            best = i;
        }
    }
    for(int i = 0 ;i<n;i++){
        ans += need[i]*cost[i];
    }
    cout<<ans<<endl;
}

5)POJ 1017
题意:
一个工厂制造的产品形状都是长方体盒子,它们的高度都是 h,长和宽都相等,一共有六个型号,分别为1*1, 2*2, 3*3, 4*4, 5*5, 6*6。
这些产品通常使用一个 6*6*h 的长方体箱子包装然后邮寄给客户。求至少要多少个箱子。
题解:
各种讨论,遍历所有可能性

#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <math.h>
#include <queue>
using namespace std;

int main(){
    int b1,b2,b3,b4,b5,b6;
    while(cin>>b1>>b2>>b3>>b4>>b5>>b6&&(b1+b2+b3+b4+b5+b6)){
        int ans = 0;
        ans += b6;
        ans += b5;
        b1 -= b5*11;
        if(b1<0){b1 = 0;}
        ans += b4;
        int needs = b4*20;
        while(needs>0){
            if(b2>0){
                needs -= 4;
                b2--;
                continue;
            }
            if(b1>0){
                needs -= 1;
                b1--;
                continue;
            }
            break;
       }
       ans += b3/4;
       if(b3%4 != 0){
            ans++;
            int b3num = b3%4;
            int uesb2,uesb1;
            uesb1=uesb2=0;
            if(b3num==1){
                needs = 27;
                while(needs>0){
                    if(b2>0&&uesb2<5){
                        needs -= 4;
                        b2--;
                        uesb2++;
                        continue;
                    }
                    if(b1>0&&uesb1<7){
                        needs -= 1;
                        b1--;
                        uesb1++;
                        continue;
                    }
                    break;
                }
            }
            if(b3num==2){
                needs = 18;
                while(needs>0){
                    if(b2>0&&uesb2<3){
                        needs -= 4;
                        b2--;
                        uesb2++;
                        continue;
                    }
                    if(b1>0&&uesb1<6){
                        needs -= 1;
                        b1--;
                        uesb1++;
                        continue;
                    }
                    break;
                }
            }
            if(b3num==3){
                needs = 9;
                while(needs>0){
                    if(b2>0&&uesb2<1){
                        needs -= 4;
                        b2--;
                        uesb2++;
                        continue;
                    }
                    if(b1>0&&uesb1<5){
                        needs -= 1;
                        b1--;
                        uesb1++;
                        continue;
                    }
                    break;
                }
            }
       }
       ans += b2/9;
       if(b2%9!=0){
            ans++;
            needs = 36 - b2%9*4;
            b1 -= needs;
            if(b1<0){b1 = 0;}
       }
       ans += b1/36;
       if(b1%36!=0){
            ans++;

       }
       cout<<ans<<endl;
    }
}

6)POJ 3040
题意:
你有N种硬币,每种若干个,硬币的面值是一种倍数关系,你每次取不少于c面值的硬币,问可以最多去几次
题解:
正是由于面值是一种倍数关系,贪心策略就是从大到小能取多少取多少但不能超过c,然后从小到大,能取多少取多少,直到刚好超过或等于c
用need数组来存在当前情况下的最优解,然后再重复找最优解,直到找不到。

 if(sum>0){
     break;
  }

结束条件

 min(cstr[i].num - need[i],(sum + cstr[i].v-1)/cstr[i].v);

对于从小到大取,每次只允许刚刚好超过c或者等于c

#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <math.h>
#include <queue>
#include <stdio.h>
#include <cstdio>
#include <string.h>
using namespace std;
struct coin{
int v;
int num;
}cstr[30];

bool cmp(coin c1,coin c2){
    return c1.v>c2.v;
}

int main(){
    int n,c;
    cin>>n>>c;
    for(int i = 0;i<n;i++){
        cin>>cstr[i].v>>cstr[i].num;
    }
    int ans = 0;
    sort(cstr,cstr+n,cmp);
    for(int i =0 ;i<n;i++){
        if(cstr[i].v>=c){
            ans += cstr[i].num;
            cstr[i].num = 0;
        }
        if(cstr[i].v<c){break;}
    }
    int need[25];
    memset(need,0,sizeof(need));
    while(1){
        int sum = c;
        memset(need,0,sizeof(need));
        for(int i = 0;i<n;i++){
            if(cstr[i].num>0&&sum > 0){
                int use = min(cstr[i].num,sum/cstr[i].v);
                if(use >0){
                    sum -= use * cstr[i].v;
                    need[i] = use;
                }

            }
        }
        for(int i = n-1;i>=0;i--){
            if(sum>0&&cstr[i].num>0){
                int use  = min(cstr[i].num - need[i],(sum + cstr[i].v-1)/cstr[i].v);
                if(use > 0){
                    sum -= use * cstr[i].v;
                    need[i] += use;
                }
            }
        }
        if(sum>0){
            break;
        }
        int add = 0x7f7f7f7f;
        for(int i =0;i<n;i++){
            if(need[i]==0){
                continue;
            }
            add = min(add,cstr[i].num/need[i]);
        }
        ans += add;
        for(int i = 0;i<n;i++){
            cstr[i].num -= need[i] *add;
        }
    }
    cout<<ans<<endl;

}


7)POJ 1862
题目大意:科学家发现一种奇怪的玩意,他们有重量weight,如果他们碰在一起,总重变成2*sqrt(m1*m2)。要求出最终的重量的最小值。
题解:
按照二元二次方程,当俩书越接近,所求的值越小

#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <math.h>
#include <queue>
#include <stdio.h>
#include <cstdio>
#include <string.h>
using namespace std;

bool cmp(double a,double b){
    return a>b;
}

int main(){
    int n;
    cin>>n;
    double num[105];
    for(int i =0;i < n;i++){
        cin>>num[i];
    }
    sort(num,num+n,cmp);
    for(int i = 0;i<n-1;i++){
        double newnum = 0;
        newnum = 2*sqrt(num[i]*num[i+1]);
        num[i+1] = newnum;
        sort(num+i+1,num+n,cmp);
    }
    printf("%.3f\n",num[n-1]);
}

8)POJ 3262
题意:
有n个牛在FJ的花园乱吃。
所以FJ要赶他们回牛棚。
每个牛在被赶走之前每秒吃Di个花朵。赶它回去FJ要花的时间是Ti。在被赶走的过程中牛就不能乱吃了
题解:
每次你赶走的都是当前情况下单位时间吃的最多的牛

#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <math.h>
#include <queue>
#include <stdio.h>
#include <cstdio>
#include <string.h>
using namespace std;
typedef pair<int ,int> p;
bool cmp(p a,p b){
    return a.first * b.second < b.first * a.second;
}

int main(){
    int n;
    cin>>n;
    p cow[100005];
    long long sum = 0;
    long long ans = 0;
    for(int i =0;i<n;i++){
        cin>> cow[i].first>>cow[i].second;
        sum += cow[i].second;
    }
    sort(cow,cow+n,cmp);
    for(int i = 0;i<n;i++){
        sum -= cow[i].second;
        ans += sum *cow[i].first*2;
    }
    cout<<ans<<endl;
}

5.优先队列
1)POJ 2010
题意:
有个学校,从c个学生中挑n个学生,要求每个学生的资助金总和<=f
求符合条件的选择方案中中学生成绩中位数的最大值
题解:
有一个lower数组,记录当第i个人是中位数时候,前面的人所需要的资金的最小值,同理有一个upper数组
lower[i] = q.size() == half ? total : 0x3f3f3f3f;
total是当前最小值

if (q.size() > half)
            {
                total -= q.top(); q.pop();
            }

因为这句话保证了当前最小

#include <iostream>
#include <algorithm>
#include <queue>
#include<stdio.h>
#include<string.h>
using namespace std;
#define MAX_COW 100000 + 16
int N, C;
long long F;
pair<int, int> cow[MAX_COW];
int lower[MAX_COW], upper[MAX_COW];
int main()
{
    cin >> N >> C >> F;
    int half = N / 2;
    for (int i = 0; i < C; ++i)
    {
        scanf("%d%d",&cow[i].first,&cow[i].second);
    }

    sort(cow, cow + C);
    {
        int total = 0;
        priority_queue<int> q;
        for (int i = 0; i < C; ++i)
        {
            lower[i] = q.size() == half ? total : 0x3f3f3f3f;
            q.push(cow[i].second);
            total += cow[i].second;
            if (q.size() > half)
            {
                total -= q.top(); q.pop();
            }
        }
    }

    {
        int total = 0;
        priority_queue<int> q;
        for (int i = C - 1; i >= 0; --i)
        {
            upper[i] = q.size() == half ? total : 0x3f3f3f3f;
            q.push(cow[i].second);
            total += cow[i].second;
            if (q.size() > half)
            {
                total -= q.top(); q.pop();
            }
        }
    }

    int result = -1;
    for (int i = C - 1; i >= 0; --i)
    {
        if (lower[i] + cow[i].second + upper[i] <= F)
        {
            result = cow[i].first;
            break;
        }
    }

    printf("%d\n",result);
    return 0;
}

2)POJ 3614
题意:
有一些牛,每只只能涂大于等于a小于等于b spf的防晒霜,
现在我们有一些防晒霜,给出他的spf和量,求最多可以涂好多只牛
题解:
遍历每一个防晒霜,当牛的可能可以接受这个防晒霜时候,就加入队列,每次排头的是最小的那个,然后每次检测队列里面的值是不是符合要求,是就ans++,不是就再也找不出符合他的了,因为防晒霜也是从小到大spf排列的

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
#define pr(x) cout<<#x<<" "<<x;
#define pl(x) cout<<#x<<" "<<x<<endl;
#include<math.h>
#include<algorithm>
using namespace std;
typedef pair<int ,int> p;
int main(){
    int c,l;
    cin>>c>>l;
     priority_queue <int,vector<int>,greater<int> > que;
     p scow[2505];
     p spf[2505];
    for(int  i = 0;i<c;i++){
        cin>>scow[i].first>>scow[i].second;
    }
    for(int  i = 0;i<l;i++){
        cin>>spf[i].first>>spf[i].second;
    }
    sort(scow,scow+c);
    sort(spf,spf+l);
    int ans = 0;int j =0;
    for(int  i= 0;i<l;i++){

            while(j<c&&spf[i].first >= scow[j].first){
                que.push(scow[j].second);j++;
            }
            while(!que.empty()&&spf[i].second>0){
                int x = que.top();
                que.pop();
                if(x<spf[i].first)continue;
                ans++;
                spf[i].second--;

            }
        }

    cout<<ans<<endl;


}

6.并查集
1)POJ 2236
题意:
有n台电脑,都是坏的,现在可以执行两种操作,修好某台电脑,判断俩电脑是否相连(可传递相连)
给你电脑坐标和最大相连距离(即电脑好的且小于等于这个距离,就表示相连)
题解:
很简单,建立并查集,还有isok数组,表示电脑是否ok,对于每一个O操作都要将所有和他相连的都uint

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
#define pr(x) cout<<#x<<" "<<x;
#define pl(x) cout<<#x<<" "<<x<<endl;
#include<math.h>
#include<algorithm>
#define ll long long
using namespace std;
int dx[1005];
int dy[1005];
bool isok[1005];
int fa[1005];
int n, d;
int init(int n){
    for(int i = 0 ;i < n;i++){
        fa[i] = i;
        isok[i] = false;
    }
}
int find(int i){
    if(i != fa[i]){
        fa[i] = find(fa[i]);
    }
    return fa[i];

}
bool dis(int i, int j){
    int a = dx[i] - dx[j];
    int b = dy[i] - dy[j];
    if(a*a + b*b <= d*d){
        return true;
    }
    return false;
}

int main(){

    cin >> n >> d;
    init(n);
    for(int i = 0;i < n; i++){
        cin >> dx[i] >> dy[i];
    }
    char ch;
    while(cin >> ch){
        if(ch == 'O'){
            int r;
            cin >> r;
            isok[r-1] = true;
            for(int i = 0;i <n;i++){
                if(i != r-1 && isok[i] && dis(i,r-1)){
                    int a = find(r-1);
                    int b = find(i);
                    fa[a] = b;
                }
            }
        }
        if(ch == 'S'){
            int a,b;
            cin >> a >> b;
            int k,j;
            k = find(a-1);
            j = find(b-1);
            if(k == j){
                cout<<"SUCCESS"<<endl;
            }
            else{
                cout<<"FAIL"<<endl;
            }
        }
    }

    return 0;
}

2)POJ 1703
题意:
有两个帮派,给你A信息,让你输出这两人是不是一个帮派的;给你D信息,表示这俩人不是一个帮派的,给你A信息后,每次输出你的回答
题解:
又是简单的并查集,但是很坑的就是cin会超时,然后并不知道是不是cout和scanf这种出现了不可预知到错误,然后就是init少了一个,唉,这题还是应该注意编号啊,以后就直接按编号来,别没事都从0开始

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
#define pr(x) cout<<#x<<" "<<x;
#define pl(x) cout<<#x<<" "<<x<<endl;
#include<math.h>
#include<algorithm>
using namespace std;
#define MAX_LEN 200010
int fa[MAX_LEN];
int ranks[MAX_LEN];
void init(int n){
    for(int i = 0;i<n;i++){
        fa[i] = i;
        ranks[i] = 0;
    }
}
int find(int i){
    if(i == fa[i]){return i;}
    else{
        return fa[i] = find(fa[i]);
        //return fa[i];

    }
}
void uint(int a, int b){
    int x = find(a);
    int y = find(b);
    if(x == y){return ;}
    else{
        if(ranks[x] > ranks[y]){
            fa[y] = x;
        }
        else{
            fa[x] = y;
            if(ranks[x]==ranks[y]){
                ranks[y]++;
            }
        }
    }

}
bool same(int i,int j){
    return find(i)==find(j);
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m;
        scanf("%d%d",&n,&m);
        init(2*n+2);
        //getchar();
        char ch;int a,b;
        while(m--){
          getchar();
            scanf("%c%d%d",&ch,&a,&b);
            //getchar();
            if(ch =='A'){
                if(same(a,b)){
                    puts("In the same gang.");
                   // cout << "In the same gang." << endl;//continue;
                }
                 else if(same(a,b+n)){
                     puts("In different gangs.");
                   // cout << "In different gangs." << endl;
                    //continue;
                }
                else{
                    puts("Not sure yet.");
                  // cout<<"Not sure yet."<<endl;
                  // continue;
                }

            }
            else {
                uint(a,b+n);
                uint(a+n,b);
            }
        }
    }
    return 0;

}

3)AOJ 2170
题意:
有一个树,有些节点染色,每次有两种操作,第一,统计该节点到离它最近的染色父亲结点的的数值,第二,为某一个节点染色
题解:
直接记录了每一个节点的父亲节点,每一次搜索就计算到他的染色父亲结点为止

#include <iostream>
#include<stdio.h>
#define MAX_N 100005
using namespace std;
typedef long long ll;
typedef pair<int ,bool> p;
p fa[MAX_N];
int main(){
    int n,q;
    fa[1].first = 1;
    fa[1].second = true;
    while(~scanf("%d%d",&n,&q)&&n>0){
        ll ans = 0;
        for(int i = 2;i <= n;i++){
            scanf("%d",&fa[i].first);
            fa[i].second = false;
        }
        getchar();
        for(int i = 0;i<q;i++){
            char ch;int a;
            scanf("%c%d",&ch,&a);
            getchar();
            if(ch =='Q'){
                while(fa[a].second==false){
                    a = fa[a].first;
                }
                ans += a;
            }
            else{
                fa[a].second = true;
            }

        }
        printf("%lld\n",ans);
    }
}

多校篇
1)2016.7.21 多校赛 1001
题意:已知一个n维向量,现在你找一个n维向量,向量每个元素都是a(a>=0),每个元素符号未知,求差向量长度的最小值。

题解:
可以直接展开为一元二次函数,公式最值求解

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
#define pr(x) cout<<#x<<" "<<x;
#define pl(x) cout<<#x<<" "<<x<<endl;
#include<math.h>
#include<algorithm>
using namespace std;
int main(){
    int n;
    cin>>n;
    while(n--){
      long long l;
      cin>>l;
      long long  s[l+5];
      long long sum = 0;
      long long sum2 = 0;
      for(int i=1;i<=l;i++){
        cin>>s[i];
        sum+=abs(s[i]);
        sum2 +=s[i]*s[i];
      }

      long long p = __gcd(l*sum2 -sum*sum,l);
      long long ans1 = (l*sum2 -sum*sum)/p;
      long long ans2 = l/p;
       cout<<ans1<<'/'<<ans2<<endl;
    }





}

2)2016.7.21 多校赛 1009
题意:
一个非增数列,数字范围[0,100],已知部分数字,求前两个数/总和的最大值
题解:
先记录已知数字,特判第一第二个,其他未知位置上,未知数字用后面最靠近它的已知数字赋值,后面没有已知数字,那么就让他是0
注意:
输出使用到__gcd()库函数,求最大公约数,在头文件#include<algorithm>

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
#define pr(x) cout<<#x<<" "<<x;
#define pl(x) cout<<#x<<" "<<x<<endl;
#include<math.h>
#include<algorithm>
using namespace std;
int main(){
    int n;
    cin>>n;
    while(n--){
        int length,know;
        cin>>length>>know;
        int index;
        int indexnum;
        int s[length+5];
        memset(s,0,sizeof(s));
        if(know!=0){
            for(int i=1;i<=know;i++){
                cin>>index>>indexnum;
                s[index] = indexnum;
            }
        }
        if(length==2){cout<<1<<'/'<<1<<endl;continue;}
        for(int i=1;i<=length;){
            if(i==1&&s[i]==0){s[i]=100;i++;continue;}
            if(i==1&&s[i]!=0){i++;}
            if(i==2&&s[i]==0){s[i]=s[1];i++;continue;}
            if(i==2&&s[i]!=0){i++;}
            if(i>2){
                if(s[i]!=0){i++;}
                else{
                    for(int j = i+1;j<=length;){
                        if(s[j]==0){j++;}
                        else{
                            s[i]=s[j];break;
                        }
                    }
                    i++;
                }
            }

        }
        int sum=0;
        for(int i=0;i<=length;i++){
            sum+=s[i];
        }
        int p = __gcd(sum,s[1]+s[2]);
        cout<<(s[1]+s[2])/p<<'/'<<sum/p<<endl;
    }
}


其他
POJ 2429 关于gcd和lcm的逆求
(较大数质因数分解pollard_rho和较大数质数检测miller_rabin)
http://wenku.baidu.com/view/fbbed5a5f524ccbff12184af.html
讲两个算法的文档

题意:
给你两个数的gcd和lcm,求他们的值
如果有多组解,输出他们值和最小的那组解
题解:
对lcm/gcd这个数字质因数分解,为了让他满足gcd和lcm不变,每一种质因数只能存在于一个数字,所以先分解质因数,但对于较大的数是不是质数的判断要用miller_rabin,对一个较大数的质因数分解需要pollard_rho,返回一个大叔随机的质因数因子。
小的素数我们可以打表筛发处理,大叔检验它是不是素数只能使用miller_rabin

#include <iostream>
#include<stdio.h>
#include<string>
#include<map>
#include<vector>
#include<stdlib.h>
typedef long long ll;
using namespace std;

ll mod_mult(ll a,ll b,ll m){
    ll res = 0;
    ll exp = a % m;
    while(b){
        if(b & 1){
            res += exp;
            res = res % m;
        }
        exp <<= 1;
        exp =exp % m;
        b >>= 1;

    }
    return res;
}

ll mod_exp(ll a,ll b,ll m){
    ll res = 1;
    ll exp = a % m;
    while(b){
        if(b & 1)
        res = mod_mult(res,exp,m);
        exp = mod_mult(exp,exp,m);
        b >>= 1;
    }
    return res;

}
bool miller_rabin(ll n, ll times)
{
    if (n < 2) return false;
    if (n == 2) return true;
    if (!(n & 1)) return false;

    ll q = n - 1;
    int k = 0;
    while (q % 2 == 0) {
        k++;
        q >>= 1;
    }
    // n - 1 = 2^k * q (q是奇素数)
    // n是素数的话,一定满足下面条件
    // (i) a^q ≡ 1 (mod n)
    // (ii) a^q, a^2q,..., a^(k-1)q 中的某一个对n求模为-1
    //
    // 所以、当不满足(i)(ii)中的任何一个的时候,就有3/4的概率是合成数
    //
    for (int i = 0; i < times; ++i)
    {
        ll a = rand() % (n - 1) + 1; // 从1,..,n-1随机挑一个数
        ll x = mod_exp(a, q, n);
        // 检查条件(i)
        if (x == 1) continue;
        // 检查条件(ii)
        bool found = false;
        for (int j = 0; j < k; j++)
        {
            if (x == n - 1)
            {
                found = true;
                break;
            }
            x = mod_mult(x, x, n);
        }
        if (found) continue;

        return false;
    }
    return true;
}
ll get_gcd(ll n, ll m)
{
    if(m == 0){return n;}
    return get_gcd(m , n%m);
}

ll pollard_rho(ll n, int c)
{
    ll x = 2;
    ll y = 2;
    ll d = 1;
    while (d == 1)
    {
        x = mod_mult(x, x, n) + c;
        y = mod_mult(y, y, n) + c;
        y = mod_mult(y, y, n) + c;
        d = get_gcd((x - y >= 0 ? x - y : y - x), n);
    }
    if (d == n) return pollard_rho(n, c + 1);
    return d;
}
#define MAX_PRIME 200000
vector<int> primes;
vector<bool> is_prime;
void init_primes(){
    is_prime = vector<bool>(MAX_PRIME + 1,true);
    is_prime[0] = is_prime[1] = false;
    for(int i =2;i<=MAX_PRIME;i++){
        if(is_prime[i]){
            primes.push_back(i);
            for(int j = i*2;j<=MAX_PRIME;j+=i){
                is_prime[j] = false;

            }
        }

    }
}
bool isprime(ll n){
    if(n <= MAX_PRIME)return is_prime[n];
    else return miller_rabin(n,20);
}
void factorize(ll n,map<ll,int> &factors){
    if(isprime(n)){
        factors[n]++;
    }
    else{
        for(int i = 0;i<primes.size();i++){
            int p = primes[i];
            while(n % p == 0){
                factors[p]++;
                n /= p;
            }
        }
        if(n != 1){
           if(isprime(n)){
                factors[n]++;
           }
           else{
                ll d = pollard_rho(n,1);
                factorize(d,factors);
                factorize(n/d,factors);
           }
        }
    }

}
pair<ll,ll> solve(ll a,ll b){
    ll c = b/a;
    map <ll,int> factors;
    factorize(c,factors);
    vector<ll> mult_factors;
    for(map<ll,int>::iterator it = factors.begin();it != factors.end();it++){
        ll mul =1;
        while(it -> second){
            mul *= it->first;
            it->second--;
        }
        mult_factors.push_back(mul);
    }
    ll best_sum = 1e18,best_x = 1,best_y = c;
    for(int mask = 0;mask<(1<<mult_factors.size());mask++){
        ll x = 1;
        for(int i = 0;i < mult_factors.size();i++){
            if(mask & (1 << i))x *= mult_factors[i];

        }
        ll y = c / x;
        if(x < y&&x+y<best_sum){
            best_sum = x+ y;
            best_x = x;
            best_y = y;

        }
    }

    return make_pair(best_x*a,best_y*a);

}
int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);
    init_primes();
    ll a, b;
    while (cin >> a >> b)
    {
        pair<ll, ll> ans = solve(a, b);
        cout << ans.first << " " << ans.second << endl;
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值