【Author : DS】CF #140 非常好的一套CF题目,DIV1 的E题实在没辙

DIV 2 A

给三个点,为从A - B - C的过程中,是要向左转还是右转还是直行。

方法很简单,叉积嘛。

#define typec long long
struct Point2D{
    typec x,y;
    Point2D(){}
    Point2D(typec _x,typec _y):x(_x),y(_y){};
    void input(){
        cin >> x >> y;
    }
    void output(){
        printf("%.2f %.2f\n",x,y);
    }

    typec len(){
        return hypot(x,y);
    }
    typec len2(){
        return x*x+y*y;
    }
    typec distance(Point2D p){
        return hypot(x-p.x,y-p.y);
    }
    Point2D add(Point2D p){
        return Point2D(x+p.x,y+p.y);
    }
    Point2D sub(Point2D p){
        return Point2D(x-p.x,y-p.y);
    }
    Point2D mul(typec b){
        return Point2D(x*b,y*b);
    }
    Point2D div(typec b){
        return Point2D(x/b,y/b);
    }
    typec dot(Point2D p){
        return x*p.x+y*p.y;
    }
    typec det(Point2D p){
        return x*p.y-y*p.x;
    }
    typec rad(Point2D a,Point2D b){
        Point2D p=*this;
        return fabs(atan2(fabs(a.sub(p).det(b.sub(p))),a.sub(p).dot(b.sub(p))));
    }
} A, B, C ,D , E;
int main(){
    A.input();
    B.input();
    C.input();
    D = B.sub(A);
    E = C.sub(A);
    LL res = D.det(E);
    if (res == 0) cout << "TOWARDS" <<endl;
    else if (res < 0) cout << "RIGHT" << endl;
    else cout << "LEFT" << endl;
}


DIV 2 B

给一个序列,给Q个查询。第一个人每次从左往右找,第二个人每次从右往左找,问分别需要查询几次。

更水,直接Map一下就好了。

map<LL , LL> Mengl , Mengr;
const int N = 200000;
LL a[N];
int n;
void solve(){
    Mengl.clear();
    Mengr.clear();
    for (int i = 1 ; i <= n ; ++i){
        cin >> a[i];
        if (Mengl.find(a[i]) == Mengl.end()) Mengl[a[i]] = i;
    }
    for (int i = n ; i >= 1 ; --i){
        if (Mengr.find(a[i]) == Mengr.end()) Mengr[a[i]] = n - i + 1;
    }

    int m ;
    cin >> m;
    LL ansa = 0 , ansb = 0;
    while (m--){
        LL x;
        cin >>x;
        ansa += Mengl[x];
        ansb += Mengr[x];
    }
    cout << ansa << " " << ansb << endl;
}
int main(){
    while (cin >> n) solve();
}


A

题意是: a , b ,c 三个站, 有1~n三个人站在a上面,如果有一个人要从 x -> y 的话那么这个人的编号必须是 x , y 中所有人中编号最大的。求移动次数。

对于n个数来说需要经历以下几步:

n      _    _                0

1      _    n-1         f(n-1)

_      1    n-1            1

n-1  1     _           f(n-1)

n-1  _     1               1

_      _     n           f(n-1)


所以 f(n) = 3 * f(n-1) + 2

于是 f(n) + 1 = 3 * (  f(n - 1)  + 1)

于是就能推出来 f(n)  =  3 ^ n - 1

注意 -1 和Mod m 的关系


#define typec long long
typec powerMod(typec x, typec k, typec m)
{
    typec res = 1;
    while(x %= m, k)
    {
        if(k&1) res *= x, res %= m;
        x *= x, k >>=1;
    }
    return res;
}
#define LL long long
LL n , m;
int main(){
    while (cin >> n >> m){
        LL res = powerMod(3LL , n , m);
        res = (res - 1LL + m) % m;
        cout << res << endl;
    }
}


B

给n个堆,每次合并的代价是较小值。

Q个询问,每次给一个k , 每一堆最多被加k次,问最少要用多少代价合并为一堆。

Orz孟神V587

贪心, 先sort 一下

f[i][j] 代表 前i堆合并为j堆的最小代价。 最终求的就是f[n][1]

f[i][j] = f[i - j][j * k] + sum[i - j] .即按照 k ^ p 递归, 每次是用前 k ^ p 堆分别放到 k ^ (p - 1) 堆

特判 k = 1 的情况,否则可能超时 

const int N = 200000;
LL a[N] , sum[N] , pre[N];
LL n , Q , k;
vector<LL> ans;

LL getans(LL idx , LL number){

    LL ret = 0;

    while (idx >= number){
        ret += sum[idx - number];
        idx -= number;
        number *= k;
    }

    return ret;
}
void solve(){
    a[0] = sum[0] = 0;
    for (int i = 1 ; i <= n ; ++i)
        cin >> a[i];

    sort(a + 1 , a + n + 1);

    for (int i = 1 ; i <= n ; ++i){
        sum[i] = sum[i - 1] + a[i];
        pre[i] = pre[i - 1] + sum[i];
    }

    ans.clear();

    cin >> Q;
    while (Q--){
        cin >> k;
        if (k == 1) ans.PB(pre[n - 1]);
        else{
            ans.PB( getans(n , 1) );
        }
    }

    for (int i = 0 ; i < ans.size(); ++i){
        if (i) printf(" ");
        cout << ans[i];
    }
    cout << endl;
}
int main(){
    while (cin >> n) solve();
}



C

首先Fibonacci数列有性质 : GCD(   f[i]  ,  f[j]   ) = f [  GCD(i , j)  ]

所以也就是求 [l  , r ] 中 k 个数 的最大公约数是几。    注意,这里没有单调性,所以不能二分!!!!

因为 函数   r / x - (l - 1) / x 分段单调( 在  r / x  =  r / y ) 上单调。

所以只需要  段内  x 最大即可。

于是枚举 i = 1 ~ \sqrt{r}   中 i 和  r / i 即可

#define LL long long
const int maxn=2;
#define typec LL
LL modo;
class Mat
{
public:
       int Matn,Matm;
       typec a[maxn][maxn];
       Mat()
       {
            Matn=0;
            Matm=0;
            memset(a,0,sizeof(a));
       }
       void output();
       void init();
       void initI();
       Mat mul(const Mat &a);
       Mat power(const Mat&a,LL k);
};
void Mat::output()
{
     for (int i=0;i<Matn;++i)
     {
         for (int j=0;j<Matm;++j)
         {
             if (j!=0) printf(" ");
             printf("%d",a[i][j]);
         }
         printf("\n");
     }
}
void Mat::init()
{
    Matn=0;
    Matm=0;
    memset(a,0,sizeof(a));
}
Mat Mat::mul(const Mat &A)
{
    Mat c;
    c.Matn=Matn;
    c.Matm=A.Matm;
    for (int i=0;i<Matn;++i)
        for (int j=0;j<A.Matm;++j)
        {
            for (int k=0;k<Matm;++k)
            {
                c.a[i][j]=(c.a[i][j]+(a[i][k]*A.a[k][j])%modo)%modo;
            }
        }
    return c;
}
void Mat::initI()
{
     memset(a,0,sizeof(a));
     for (int i=0;i<Matn;++i) a[i][i]=1LL;
}
Mat Mat::power(const Mat& a,LL  k)
{
    Mat c=a,b;
    b.init();
    b.Matn=a.Matn;b.Matm=a.Matm;
    b.initI();
    while (k)
    {
         if (k & 1LL)
            b=b.mul(c);
         c=c.mul(c);
         k>>=1LL;
    }
    return b;
}
LL gao(LL t){
    if (t <= 1) return 1LL;
    Mat a;
    a.Matm = a.Matn = 2;
    a.a[0][0] = 1LL , a.a[1][0] = 1LL , a.a[0][1] = 1LL;
    a = a.power(a , t - 1LL);
    return a.a[0][0];
}
LL l , r , k;
/*
1000000000 1 1000000000000 5
*/
LL check(LL x){
    return r / x - (l - 1LL) / x;
}
void solve(){
    LL ans = 1;
    for (LL i = 1 ; i * i <= r ; ++i){
        if (check(i) >= k && i > ans) ans = i;
        LL j = r / i;
        if (check(j) >= k && j > ans) ans = j;
    }
    cout << gao(ans) % modo <<endl;
}


D

给一个100 * 100 的数阵 , 每次可以转换一行或者一列的正负。求一个解,使得每行每列的和都>=0

每次找到最小的一行或者一列, 反一下就行了。。

const int N = 200;
int a[N][N];
int suml[N] , sumc[N];
bool reversel[N] ,reversec[N];
int n , m;
void rev(int x , int y){
    suml[x] -= 2 * a[x][y];
    sumc[y] -= 2 * a[x][y];
    a[x][y] = -a[x][y];
}
void revl(int line){
    reversel[line] ^= 1;
    for (int i = 0 ; i < m ; ++i)
        rev(line , i);
}
void revc(int column){
    reversec[column] ^= 1;
    for (int i = 0 ; i < n ; ++i)
        rev(i , column);
}
void solve(){
    memset(suml , 0 , sizeof(suml));
    memset(sumc , 0 , sizeof(sumc));
    memset(reversel , 0 , sizeof(reversel));
    memset(reversec , 0 , sizeof(reversec));
    for (int i = 0 ; i < n ; ++i)
        for (int j = 0 ; j < m ; ++j){
            cin >> a[i][j];
            suml[i] += a[i][j];
            sumc[j] += a[i][j];
        }
    int ml , mc , sl , sc;
    do{
        ml = min_element(suml , suml + n) - suml;
        mc = min_element(sumc , sumc + m) - sumc;
        //printf("%d %d\n",suml[ml] , sumc[mc]);

        sl = suml[ml] , sc = sumc[mc];
        if (suml[ml] <= sumc[mc] && suml[ml] < 0) revl(ml);
        else if (sumc[mc] < suml[ml] && sumc[mc] < 0) revc(mc);
    }while (sl < 0 || sc < 0);

    int ansl = 0 , ansc = 0;
    for (int i = 0 ; i < n ; ++i)
        if (reversel[i]) ++ansl;
    for (int i = 0 ; i < m ; ++i)
        if (reversec[i]) ++ansc;

    printf("%d",ansl);
    for (int i = 0 ; i < n ; ++i)
        if (reversel[i]) printf(" %d",i + 1);
    printf("\n");

    printf("%d",ansc);
    for (int i = 0 ; i < m ; ++i)
        if (reversec[i]) printf(" %d", i + 1);
    printf("\n");
}
int main(){
    while (cin >> n >> m) solve();
}



你可能感兴趣的:(c,input,div,output,distance)