• 《牛客练习赛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:咕咕咕.

  • 相关阅读:
    Java for LeetCode 229 Majority Element II
    Java for LeetCode 228 Summary Ranges
    Java for LeetCode 227 Basic Calculator II
    Java for LintCode 颜色分类
    Java for LintCode 链表插入排序
    Java for LintCode 颠倒整数
    Java for LintCode 验证二叉查找树
    Java for LeetCode 226 Invert Binary Tree
    Java for LeetCode 225 Implement Stack using Queues
    Java for LeetCode 224 Basic Calculator
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/13122230.html
Copyright © 2020-2023  润新知