zoukankan      html  css  js  c++  java
  • The Preliminary Contest for ICPC Asia Nanjing 2019ICPC南京网络赛

    B.super_log (欧拉降幂)

    •题意

    定一个一个运算log*,迭代表达式为

    给定一个a,b计算直到迭代结果>=b时,最小的x,输出对m取余后的值 

    •思路

    $log*_{a}(1)=1+log*_{a}(0)=1-1=0$          

    $log*_{a}(a)=1+log*_{a}(log_{a}(a))=1+log*_{a}(1)=1$    

    $log*_{a}(a^{a})=1+log*_{a}(a)=2$                           

    ....

    以此类推得$log*_{a}(a^{a^{a^{a^{a^{...}}}}})=b$    (共b个a) 

    接下来接转化为$a^{a^{a^{a^{a^{...}}}}}$  (共b个a)  对m取模得结果

    ps.如果对欧拉降幂不熟悉的话可以先看一下这个题(戳我~)

    利用欧拉降幂

    $a^{b}=egin{cases}a^{b\%varphi(p)}    gcd(a,p)=1 \ a^{b}    gcd(a,p) eq 1,b leqslant varphi(p)\a^{b\%varphi(p)+varphi(p)}  gcd(a,p) eq1,bgeqslant varphi(p)  \ end{cases}$

    递归求解,至多走到2log层模数就会变成1,返回答案就行了。

    但是在求$a^{a}\%varphi(p)$时怎么计算$a$和$varphi(p)$的大小呢

    利用取模方法!

    在取模时,如果大于$varphi(p)$就取模 x=x%mod,否则不取模x=x,就可以当作a和p的互素处理

    具体证明请看这里

     •代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 ll qpow(ll a,ll b,ll mod)//快速幂
     5 {
     6     ll res=1;
     7     while(b)
     8     {
     9         if(b&1)
    10             res=res*a>mod?res*a%mod+mod:res*a;
    11         a=a*a>mod?a*a%mod+mod:a*a;
    12         b>>=1;
    13     }
    14     return res;
    15 }
    16 
    17 ll phi(ll x)//求x的欧拉函数值
    18 {
    19     ll res=x;
    20     for(int i=2;i*i<=x;i++)
    21     {
    22         if(x%i==0)
    23         {
    24             while(x%i==0)
    25                 x/=i;
    26             res=res-res/i;
    27         }
    28     }
    29     if(x>1)
    30         res=res-res/x;
    31     return res;
    32 }
    33 
    34 ll solve(ll a,ll b,ll m)
    35 {
    36     if(m == 1)
    37         return 0;
    38     if(b==0||a==1)
    39         return 1ll;
    40 
    41     ll p=phi(m);
    42     return qpow(a,solve(a,b-1,p),m);
    43 }
    44 
    45 int main()
    46 {
    47     int t;
    48     cin>>t;
    49     while(t--)
    50     {
    51         ll a,b,m;
    52         cin>>a>>b>>m;
    53         cout<<solve(a,b,m)%m<<endl;
    54     }
    55 }
    View Code

    H. Holy Grail(最短路floyd)

     •题意

    给一个加权有向图,然后让你给你六个顶点,添六条边,

    但是添边是有限制的。每次添边的权值要最小,并且不能构成负环,

     •思路

    可以先根据已知边跑floyd,获得此时两点u->v的最短路,然后v->u的权值等于u->v的最短路取反

    然后再根据此时已知边继续跑floyd,再加边

    进行6次floyd,加6条边

     dij不能处理负权pass!

    (在比赛时一直在想加上u->v这条边也不能构成环的情况然后就不知道该怎么做了...

    然而看出题人题解貌似没有这个意思....??题意描述不清喵喵喵?)

     •代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define inf 0x3f3f3f3f3f3f3f3f
     5 int n,m;
     6 ll d[305][305];
     7 
     8 void Init()
     9 {
    10     for(int i=1;i<=n;i++)
    11         for(int j=1;j<=n;j++)
    12             d[i][j]=inf;
    13 }
    14 
    15 void floyd()
    16 {
    17     for(int k=1;k<=n;k++)
    18         for(int i=1;i<=n;i++)
    19             for(int j=1;j<=n;j++)
    20                 d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
    21 }
    22 int main()
    23 {
    24 //    freopen("C:\Users\14685\Desktop\C++workspace\in&out\contest","r",stdin);
    25     int t;
    26     scanf("%d",&t);
    27     while(t--)
    28     {
    29         scanf("%d%d",&n,&m);
    30         Init();
    31         int u,v;
    32         ll k;
    33         for(int i=1;i<=m;++i)
    34         {
    35             scanf("%d%d%lld",&u,&v,&k);
    36             d[u+1][v+1]=k;
    37         }
    38         for(int i=1;i<=6;++i)
    39         {
    40             floyd();
    41             scanf("%d%d",&u,&v);
    42             printf("%lld
    ",-1ll*d[v+1][u+1]);
    43             d[u+1][v+1]=-1ll*d[v+1][u+1];
    44         }
    45     }
    46 }
    View Code

    F.Greedy Sequence(思维+滑动窗口)

    •题意

      给你一个包含 n 个数的序列 a,其中 a 中存的数为 1~n 的排列;

      定义一个二维数组 s;

      s 中一共有 n 行,每行有 n 个数;

      定义 s 数组:

        ① $s_{i}[1]=i$

        ②$forall  i in[1,n],j in [2,n],s_{i,j} le s_{i,j-1}$,即 $s_i$是个非增序列;

        ③对于 $s_i$ 中的第 j( j > 1 ) 个数,$s_{i,j}$ 在 a 中的位置与 $s_{i,j-1}$ 在 a 中的位置之差的绝对值不能超过 k;

        ④ $s_i$ 中的第 j( j > 1) 个数,要尽可能的大;

        ⑤如果 $s_{i,j}$ 后,在 a 中找不到满足条件 ②③ 的数,并且 $s_i$ 不足 n 个数,用 0 填充剩余的数;

      输出 |s1|,|s2|,...,|sn|,|si|表示 s 中第 i 行包含的数的个数;

    •思路

    在set为空时插入0,是为了upper_bound()容易找,

    利用upper_bound()需要-1,如果upper_bound()=begin()的话需要判断

    插入0后就不需要判断了,方便操作

    •代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=1e5+5;
     4 int a[maxn];
     5 int R[maxn],L[maxn];
     6 int s[maxn];
     7 set<int> f;
     8 int n,k;
     9 
    10 void Solve()
    11 {
    12     f.clear();
    13     f.insert(0);
    14     int index=2;///index代表下标
    15     for(;index<=min(k+1,n);index++)
    16         f.insert(a[index]);
    17 
    18     for(int i=1;i<=n;i++)
    19     {
    20         auto it=f.upper_bound(a[i]);
    21         it--;
    22         R[a[i]]=*it;
    23         f.erase(f.find(a[i+1]));
    24         if(index<=n)
    25             f.insert(a[index++]);
    26     }
    27     f.clear();
    28     f.insert(0);
    29     index=n-1;
    30     for(;index>=max(1,n-k);index--)
    31         f.insert(a[index]);
    32 
    33     for(int i=n;i>=1;i--)
    34     {
    35         auto it=f.upper_bound(a[i]);
    36         it--;
    37         L[a[i]]=*it;
    38         f.erase(f.find(a[i-1]));
    39         if(index>=1)
    40             f.insert(a[index--]);
    41     }
    42 //    for(int i=1;i<=n;i++)
    43 //        printf("%d R:%d L:%d
    ",a[i],R[a[i]],L[a[i]]);
    44 
    45     s[0]==0;
    46     for(int i=1;i<=n;i++)
    47     {
    48         s[i]=s[max(R[i],L[i])]+1;
    49         printf("%d%c",s[i],i==n?'
    ':' ');
    50     }
    51 
    52 }
    53 int main()
    54 {
    55     int t;
    56     cin>>t;
    57     while(t--)
    58     {
    59         cin>>n>>k;
    60         for(int i=1;i<=n;i++)
    61             cin>>a[i];
    62         Solve();
    63     }
    64 }
    View Code

    I.Washing clothes(贪心)

    •题意

    有n个人分别在$t_{i}$时刻进入洗衣房要洗衣服,可以机洗可以手洗,

    但是只有一台洗衣机,每次机洗花费的时间是$x$,同时也可以手洗花费时间是$m$,

    可以多人同时手洗,而不能同时机洗

    求当$xepsilon [1,y]$,所有人所要花费的最少时间。

    •思路

     如何判断从哪个人开始使用洗衣机呢?

    我们可以使手洗时间尽可能的与机洗时间相同,找到这个点,即为最小值

    为什么这个点是最小值呢?

    因为$f(i)$是单调递增函数,$g(i)$是单调递减函数

    设两者相等时机洗$cnt$个,手洗$n-cnt$个

    ①现在让手洗多一个,机洗少一个,

      因为$f(i)$单调递增,$f(n-cnt+1)>f(n-cnt)$,所以$max(f(i),g(i))$增大,花费时间增加

    ②现在让手洗少一个,机洗多一个,

      手洗花费时间减少$f(i)<g(i)$,已经不影响最大值,而机洗时间可能增大,花费时间可能增加

    如何来计算这一点

    可以利用手洗和机洗的时间关系,计算手洗一件可以机洗cnt件,

    那后$cnt$件可以机洗,前$n-cnt$件用手洗(手洗早结束也早,所以是在cnt件机洗结束时结束)

    这里解释一下题解中机洗答案为什么是$max_{j=i}^{N}t_{j}+(n-j+1)*x$

    用洗衣机洗有两种情况:

    ①洗衣机无空闲时间。排队等着前一个人用完洗衣机后一个人接着用

      其中$t_{j}+(n-j+1)*x$其实是相当于把后面的衣服都在$j$洗完以后接着洗的,

      也就是人来了在等洗衣机洗完,洗完接着又开始洗下一个人的衣服,计算无空闲时间情况

    ②洗衣机有空闲时间。前一个人用完洗衣机,后一个人还没到,隔一段时间才到然后用洗衣机

      从i到n取最大值,其实是假设第$j$个人洗完,而第$j+1$个人还没来

      那第$j$个人肯定不会影响最大值了,第$j$个人的时间肯定在$t[j+1]$之内了,计算有空闲时间情况

    •代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 const int maxn=1e6+5;
     5 ll a[maxn];
     6 
     7 int main()
     8 {
     9     int n,m;
    10     while(~scanf("%d%d",&n,&m))
    11     {
    12         for(int i=1;i<=n;i++)
    13             scanf("%lld",a+i);
    14 
    15         sort(a+1,a+1+n);
    16 
    17         for(int i=1;i<=m;i++)
    18         {
    19             int cnt=min(n,m/i);///手洗一个能机洗的cnt个
    20             ///令手洗与机洗结束时间相同
    21             ///后cnt个机洗,前n-cnt个手洗
    22             ll ans=0;
    23             if(cnt<n)
    24                 ans=a[n-cnt]+m;///手洗所用时间
    25             for(int j=n-cnt+1;j<=n;j++)///机洗
    26                 ans=max(ans,a[j]+1ll*(n-j+1)*i);
    27 
    28             printf("%lld%c",ans,i==m?'
    ':' ');
    29         }
    30     }
    31 }
    View Code
  • 相关阅读:
    进制详解:二进制、八进制和十六进制
    学编程难吗?多久能入门?
    英语和数学不好,能学编程吗?
    C语言是菜鸟和大神的分水岭
    C语言究竟是一门怎样的语言?
    通俗地理解什么是编程语言
    哪款C语言编译器(IDE)适合初学者?
    spring task
    spring静态工厂方法得到单例bean
    多个切面表达式
  • 原文地址:https://www.cnblogs.com/MMMinoz/p/11447578.html
Copyright © 2011-2022 走看看