zoukankan      html  css  js  c++  java
  • 《牛客练习赛65》

    C:

    显然步数只存在0,1,2,3,-1的情况。随便画画就能明白.
    对于0的情况,显然是(0,0).
    对于1的情况,显然为该点在(0,0)和某点的连线上。这里可以用斜率来判断。

    还有就是如果斜率的个数 <= 1,说明无法完成,这里需要在下面的情况之前特判。
    对于2的情况。当n > 3时。都可以2步。

    对于n == 2的情况。
    如果(0,0)和两点中的某一点的连边和另外一个和查询点的连边都平行。
    说明不能两步。(这时也可以发现,这时四点成平行四边形).那么就是3步。
    事实上就是因为三点以上不可能形成平行四边形,所以肯定满足2步.
    否则就是2步。
    其他的就是-1了。
    主要还是多画画试试.

    这里几个细节。

    pii存斜率-4/1.和4/-1最后的结果一样。

    因为他们的gcd是-1,1.

    即当两个数正负不同时,gcd会根据前面那个来取符号。

    那么显然/gcd之后都是4/-1.

    然后mp[pii{}] != 0,是会增加元素的!!!.

    要用count来判断。还有就是输入的时候过滤(0,0)点。

    Code:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    const int N = 1e5+5;
    const int M = 1e6+5;
    const int Mod = 998244353;
    #define pi acos(-1)
    #define INF 1e18
    #define INM INT_MIN
    #define rg register
    #define pb(a)  push_back(a)
    #define mk(a,b) make_pair(a,b)
    #define dbg(x) cout << "now this num is " << x << endl;
    #define met0(axx) memset(axx,0,sizeof(axx));
    #define metf(axx) memset(axx,-1,sizeof(axx));
    #define sd(ax) scanf("%d",&ax)
    #define sld(ax) scanf("%lld",&ax)
    #define sldd(ax,bx) scanf("%lld %lld",&ax,&bx)
    #define sdd(ax,bx) scanf("%d %d",&ax,&bx)
    #define sddd(ax,bx,cx) scanf("%d %d %d",&ax,&bx,&cx)
    #define sfd(ax) scanf("%lf",&ax)
    #define sfdd(ax,bx) scanf("%lf %lf",&ax,&bx)
    #define pr(a) printf("%d\n",a)
    #define plr(a) printf("%lld\n",a)
    /*
    显然步数只存在0,1,2,3,-1的情况。随便画画就能明白.
    对于0的情况,显然是(0,0).
    对于1的情况,显然为该点在(0,0)和某点的连线上。这里可以用斜率来判断。
    对于2的情况。当n > 3时。都可以2步。
    对于n == 2的情况。
    如果(0,0)和两点中的某一点的连边和另外一个和查询点的连边都平行。
    说明不能两步。(这时也可以发现,这时四点成平行四边形).那么就是3步。
    事实上就是因为三点以上不可能形成平行四边形,所以肯定满足2步.
    否则就是2步。
    其他的就是-1了。
    主要还是多画画试试.
    */
    int a[N],b[N];
    double eps = 1e-13; 
    bool cal(int x1,int y1,int x2,int y2)
    {
        if(y1*x2 == y2*x1) return 1;
        else return 0;
    }
    void run()
    {
        int n,q;sdd(n,q);
        int cnt = 0,num = 0;
        map<pii,int> mp;//正,正/负
        for(int i = 1;i <= n;++i)
        {
            int x,y;sdd(x,y);
            if(x == 0 && y == 0) continue;
            int t = __gcd(x,y);
            a[++cnt] = x,b[cnt] = y;
            if(mp[pii{x/t,y/t}] == 0) num++;
            mp[pii{x/t,y/t}]++;
        }
        while(q--)
        {
            int x,y;sdd(x,y);
            if(x == 0 && y == 0) printf("0\n");
            else
            {
                int t = __gcd(x,y);
                if(mp.count(pii{x/t,y/t}) != 0) printf("1\n");
                else if(mp.size() <= 1) printf("-1\n");
                else if(cnt > 2) printf("2\n");
                else if(cnt == 2)
                {
                    if(cal(a[1],b[1],a[2]-x,b[2]-y) && cal(a[2],b[2],a[1]-x,b[1]-y)) printf("3\n");
                    else printf("2\n");
                   // printf("here\n");
                }
            }
        }
    }  
    int main()
    {
        run();
      //system("pause");
        return 0;
    }

    D:

    首先可以发现。

    对如果是质数的话,显然和其他的质数组成的lcm都是唯一的。即不会重叠..

    然后根据唯一分解定理。

    一个数n,可以分解成若干个质数pi^kI的和.

    那么很显然,如果一个数可以分解。那么就分解它。这样的价值可以最大化.

    所以可以发现,最后的集合一定是一个素数幂次组成的集合.

    那么如果进行统计。

    背包dp转移。

    因为这里需要比较大小。而背包又取模了。

    所以这里用了pair来背包。first存log后的背包值。利用log来比较大小。

    注意的是。对于一个质数,它的各个幂次加入之后。

    和前面的产生lcm都不会自身的幂次和前面产生的lcm会重叠。因为显然lcm会随着幂次的增加而扩大,而且和质数去lcm,这个lcm又无法缩小。

    所以可以证明不会和自身的幂次重叠。

    然后显然从自身的小的幂次开始加入更好。因为产生的贡献一样,代价却更小。

    所以显然对于自身幂次加入的数。应该是从小到大连续加入。

    所以这里背包对于每个质数的幂次,从1次+2次+3次这样的思路不断更新背包。

    然后这个贡献。

    显然对于每个质数。可以和前面的背包dp[j-t]的每个数都产生不同的结果。

    显然这个结果weidp[j-t]*k.

    但需要注意的是,这里是乘。和加的背包有些不一样。因为乘的话算的都是当前加入的这个数和前面的贡献。但之前dp[j-t]的贡献就会被过滤掉。

    所以应该加上之前的。即dp[j-t] + dp[j-t]*k = dp[j-t]*(k+1);

    注意边界。log = 0,dp[0] = 1.

    然后这里是一维的背包,所以倒着递推。消除后效性。

    然后这里埃氏筛,先筛素数

    Code:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    const int N = 1e5+5;
    const int M = 1e6+5;
    const int Mod = 1e9+7;
    #define pi acos(-1)
    #define INF 1e18
    #define INM INT_MIN
    #define rg register
    #define pb(a)  push_back(a)
    #define mk(a,b) make_pair(a,b)
    #define dbg(x) cout << "now this num is " << x << endl;
    #define met0(axx) memset(axx,0,sizeof(axx));
    #define metf(axx) memset(axx,-1,sizeof(axx));
    #define sd(ax) scanf("%d",&ax)
    #define sld(ax) scanf("%lld",&ax)
    #define sldd(ax,bx) scanf("%lld %lld",&ax,&bx)
    #define sdd(ax,bx) scanf("%d %d",&ax,&bx)
    #define sddd(ax,bx,cx) scanf("%d %d %d",&ax,&bx,&cx)
    #define sfd(ax) scanf("%lf",&ax)
    #define sfdd(ax,bx) scanf("%lf %lf",&ax,&bx)
    #define pr(a) printf("%d\n",a)
    #define plr(a) printf("%lld\n",a)
     
    int p[N];
    bool vis[N];
    void init(int up)
    {
        for(int i = 1;i < up;++i) vis[i] = 1;
        vis[1] = 0;int cnt = 0;
        for(int i = 2;i < up;++i)
        {
            if(vis[i]) 
            {
                p[++cnt] = i;
                for(int j = i+i;j < up;j += i) vis[j] = 0;
            }
        }
    }
    pair<double,LL> dp[N];
    int main()
    {
        init(N);
        int n;sd(n);
        LL sum=0;
        pair<double,LL> ans;
        ans.first = -1,ans.second = 0;
        dp[0].first = 0,dp[0].second = 1;
        for(int i = 1;;++i)
        {
            for(int j = n;j >= 1;--j)
            {
                LL t = p[i],tmp = p[i];
                for(int k = 1;t <= j;++k,tmp *= p[i],t += tmp)//tmp即该质数的各幂次。t一直加,因为显然是连续的幂次放入.
                {
                    pair<double,LL> ma = make_pair(dp[j-t].first+log2(k+1),dp[j-t].second*(k+1)%Mod);
                    dp[j] = max(dp[j],ma);//先比较first即log2,然后比较second。保证背包更大。
                }
            }
            sum += p[i];//当每个质数都加入一次后>n,说明不可能有更优的了。就退出。
            if(sum > n) break;
        }
    
        for(int i = 0;i <= n;++i) ans = max(ans,dp[i]);
        printf("%lld\n",ans.second);
        //system("pause");
        return 0;
    }

    E:

    最小费用最大流。

    这里的思路很巧妙。

    因为要最小化xi-yi的路径权值.

    所以用费用流来代替。

    对每个x-y之前建边。且边的流量不断+bi.

    这里就能保证了第二次走这两个点时,会走cost+b[i]*(k-1).

    但显然这样看,最小的cost+0并不会在走一次后改变,所以这里又有了最大流的思路。

    因为最大流的容量限制。在走了q后。会使q无法再走。所以就会到cost+b[i]*(k-1).

    所以这样就能得到最小的总费用。

    建图。

    每对xi-yi之前建q条边(因为有q次询问),权值不断+b[i].

    每条边的费用即为权值。容量为1.走一次即-1.

    Code:咕咕咕.

  • 相关阅读:
    Finder 的分栏显示模式宽度调整
    IBAction作用相当于void,NSLog(@"被调用的方法名是%s",__func__);
    Trapping Rain Water
    Binary Tree Preorder Traversal
    Valid Parentheses
    Reverse Words in a String | LeetCode OJ | C++
    Gas Station|leetcode 贪心
    两个字符串“相等”
    Binary Tree Zigzag Level Order Traversal
    Add Binary
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/13122230.html
Copyright © 2011-2022 走看看