• 2019 The Preliminary Contest for ICPC Asia Nanjing


    B  题目链接

    题目公式貌似复杂但实际拆解后就是power tower问题,见此处 。 想到用欧拉降幂,但是降幂时幂数的处理有点麻烦。

    有一种精巧取模方式及其证明过程,见某位大哥的证明过程

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn = 1e6;
     5 int tot=0;
     6 bool vis[maxn+6];
     7 int prime[maxn+6],totient[maxn+6];
     8 ll a,b,m;
     9 ll mmod(ll x,ll m){
    10     return x>=m?(x%m+m):x;
    11 }
    12 
    13 ll qPow(ll a,ll b,ll m){
    14     ll ret = 1ll;
    15     while(b){
    16         if(b&1) ret = mmod(ret*a,m);
    17         a = mmod(a*a,m);
    18         b >>= 1;
    19     }
    20     return ret;
    21 }
    22 
    23 void init(){
    24     totient[1] = 1;
    25     vis[1] = true;
    26     for(int i=2;i<=maxn;++i){
    27         if(!vis[i]){
    28             vis[i] = true;
    29             prime[tot++] = i;
    30             totient[i] = i-1;
    31         }
    32         for(int j=0;j<tot;++j){
    33             if(i*prime[j]>maxn) break;
    34             vis[i*prime[j]] = true;
    35             if(i%prime[j]){
    36                 totient[i*prime[j]] = totient[i] * (prime[j] - 1);
    37             }else{
    38                 totient[i*prime[j]] = totient[i] * prime[j];
    39                 break;
    40             }
    41         }
    42     }
    43 //    printf("tot %d
    ",tot);
    44 //    for(int i=1;i<=100;++i)
    45 //        cerr<<totient[i]<<endl;
    46 }
    47 
    48 ll solve(ll L ,ll R, ll p ){
    49     if(L==R||p==1) return mmod(a,p);
    50     ll ret = qPow(a,solve(L+1,R,totient[p]),p);
    51 //    printf("%lld %lld %lld %lld
    ",L,R,p,ret);
    52     return ret;
    53 }
    54 
    55 int main(){
    56     int T;
    57     scanf("%d",&T);
    58     init();
    59     while(T--){
    60         scanf("%lld%lld%lld",&a,&b,&m);
    61         if(b==0)
    62             printf("%lld
    ",1ll%m);
    63         else
    64             printf("%lld
    ",solve(1ll,b,m)%m);
    65     }
    66     return 0;
    67 }
    View Code

    这大概算是欧拉定理的活用吧。

    F  题目链接

    题目大意是给出 n 的 permutation  , 对于每一个元素 在其左右各不超过 K个数的范围里 递归地转移到不超过当前元素的最大元素上,若无则结束寻找,现在需要根据该permutation得到每一个元素的寻找链的长度。(T<=20;n,K<=1e5)

    每个元素第一个寻找的下一个位置是固定的,用尺取法+set二分 可以预处理出所有元素的第一个元素的下一个位置 <O(nlogn)>,然后记忆化搜索即可<O(n)> 。因为搜到一个点后其后的转移是固定的。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn = 1e5+5;
     4 
     5 set< int > S;
     6 int N,K;
     7 int permut[maxn];
     8 int lefnext[maxn],rignext[maxn];
     9 //bool vis[maxn];
    10 int ans[maxn];
    11 
    12 int getnext(int val){
    13     val = -val;
    14 //    auto ptr = upper_bound(S.begin(),S.end(),val);//正是此处增加了复杂度
    15     auto ptr = S.find(val);
    16     ptr++;
    17     if(ptr == S.end()) return 0;
    18     int ret =  (*ptr);
    19     ret = -ret;
    20     return ret;
    21 }
    22 
    23 int DFS(int x){
    24 //    printf("in DFS %d
    ",x);
    25     if(x<=0)
    26         return 0;
    27     if(ans[x])
    28         return ans[x];
    29     int LRnext = max(lefnext[x],rignext[x]);
    30     if(LRnext == 0)
    31         return ans[x] = 1;
    32     else
    33         return ans[x] = DFS(LRnext) + 1;
    34 }
    35 
    36 int main(){
    37 //    __clock_t stt = clock();
    38 //    __clock_t mdt;
    39     int T;
    40     scanf("%d",&T);
    41     while(T--){
    42         S.clear();
    43         scanf("%d%d",&N,&K);
    44         for (int i = 1; i <= N; ++i) {
    45             scanf("%d",&permut[i]);
    46             lefnext[i] = rignext[i] = 0;
    47 //            vis[i] = false;
    48             ans[i] = 0;
    49         }
    50 
    51         int L,R;
    52         L = 1,R=1;
    53         S.insert(-permut[R]);
    54         lefnext[permut[R]] = getnext(permut[R]);
    55         while(L<=N&&R<=R){
    56             if(R-L+1 == K+1 || R==N){
    57                 rignext[permut[L]] = getnext(permut[L]);
    58                 S.erase(-permut[L]);
    59                 L++;
    60             }
    61             else{
    62                 R++;
    63                 S.insert(-permut[R]);
    64                 lefnext[permut[R]] = getnext(permut[R]);
    65             }
    66         }
    67 
    68 //        mdt = clock();
    69 
    70         for(int i=1;i<=N;++i){
    71 //            printf("%d : %d,%d
    ",i,lefnext[i],rignext[i]);
    72             ans[i] = DFS(i);
    73         }
    74         for(int i=1;i<=N;++i)
    75             printf("%d%c",ans[i],i==N?'
    ':' ');
    76     }
    77 //    __clock_t ent = clock();
    78 //    printf("%.3lf
    ", static_cast<double>(mdt - stt)/1000.0 );
    79 //    printf("%.3lf
    ", static_cast<double>(ent - stt)/1000.0 );
    80     return 0;
    81 }
    View Code

    然而开始写的复杂度却惊人的大,后来通过随机大数据调试发现问题出在了,这一句上:

    auto ptr = upper_bound(S.begin(),S.end(),val);//正是此处增加了复杂度

    换成 "ptr = S.find(val)  ; ptr ++ ;" 后就是正常预估的复杂度。 ps : 要是 S中没有 val 怎么办?也可以先insert后再erase()。

    实际上最简单的写法是:

    auto ptr = S.upper_bound(val);

    如此也是对的。

    std::upper_bound() 与 std::set::upper_bound() 完全不同啊。要是用第一个虽然答案无异,但相当于搜了许多不必要的位置,增加了时间开销。(set不是线性存储)

    H  题目链接

    签到题。

    给一个保证无负环但可能有负权边的DAG,依次给出六个询问,每个询问给出 u ,v (保证 u -> v之前无边)两点点号, 要求在该图上建立一条 u -> v 的带权边,权值最小且必须保证加边后图仍无负环,对于每隔询问进行加边操作且回答加边权值。

    以v为起点跑 Bellman-Ford  ,然后 使加 u -> v后得到一个零权重环即可。v 到 u 是最短路,所以加新边 u -> v后 即使有其他环其权重也必然大于等于零。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 struct Edge
     5 {
     6     int from,to;
     7     ll dist;
     8 };
     9 vector<Edge> edges;
    10 vector<int> g[1005];
    11 bool inq[1005];
    12 ll d[1005];
    13 int pre[1005];
    14 int cnt[1005];
    15 int n,m;
    16 int a,b;
    17 void init()
    18 {
    19     for(int i=0;i<=n-1;i++)
    20         g[i].clear();
    21     edges.clear();
    22 }
    23 void addedge(int from,int to,ll dist)
    24 {
    25     edges.push_back((Edge){from,to,dist});
    26     int num=edges.size();
    27     g[from].push_back(num-1);
    28 }
    29 bool spfa(int s)
    30 {
    31     queue<int> q;
    32     memset(inq,0,sizeof(inq));
    33     memset(cnt,0,sizeof(cnt));
    34     memset(d,0x3f,sizeof(d));
    35     d[s]=0;
    36     inq[s]=1;
    37     q.push(s);
    38     while(!q.empty())
    39     {
    40         int u=q.front();
    41         q.pop();
    42         inq[u]=0;
    43         for(int i=0;i<g[u].size();i++)
    44         {
    45             Edge e=edges[g[u][i]];
    46             if(d[e.to]>d[u]+e.dist)
    47             {
    48                 d[e.to]=d[u]+e.dist;
    49                 pre[e.to]=g[u][i];
    50                 if(!inq[e.to])
    51                 {
    52                     q.push(e.to);
    53                     inq[e.to]=1;
    54                     if(++cnt[e.to]>n)
    55                         return false;
    56                 }
    57             }
    58         }
    59     }
    60     return true;
    61 }
    62 
    63 int main()
    64 {
    65     int T;
    66     scanf("%d",&T);
    67     while (T--) {
    68         scanf("%d%d",&n,&m);
    69         init();
    70         for(int i=0;i<=m-1;i++)
    71         {
    72             int a,b,c;
    73             scanf("%d%d%d",&a,&b,&c);
    74             addedge(a,b,c);
    75         }
    76         for (int i = 0; i < 6; ++i) {
    77             scanf("%d%d",&a,&b);
    78             if(spfa(b))
    79             {
    80                 if(d[a] == d[1004]) d[a] = -1000000000;//无路径
    81                 ll wei = d[a];
    82                 printf("%lld
    ",-1*d[a]);
    83                 addedge(a,b,-1*d[a]);
    84             }
    85         }
    86 
    87     }
    88     return 0;
    89 }
    View Code
  • 相关阅读:
    java进阶知识--File类
    java进阶知识--函数式接口
    java进阶知识--Lambda表达式、递归
    java进阶知识--线程池
    java进阶知识--线程安全
    java进阶知识--多线程入门
    java基础知识--异常
    java基础知识--可变参数
    mysql中如何不重复插入满足某些条件的重复的记录的问题
    有关map中使用iterate迭代器遍历的不保序问题和list remove(object)的细节问题
  • 原文地址:https://www.cnblogs.com/Kiritsugu/p/11447577.html
Copyright © 2020-2023  润新知