ACM2019南京网络赛

全程5小时,一题都没过。全靠队友带躺。
后来题解出来后,把比赛时两道没过的题目改了改,这里记录一下。
https://nanti.jisuanke.com/t/41299
这题在比赛时YY出了答案,a^{a^{a^{a}}} mod \;m(共\;b个\;a)
类似题目 https://blog.csdn.net/zzkksunboy/article/details/78867686
然后就是幂塔函数求模运算,但是用扩展欧拉定理实现时,遇到了大量的坑。

图片.png

换句话说,我们就要考虑两种情况。
1 a、m互质。
2 a、m不互质。
第一种情况直接计算,第二种情况,根据上一层递归的返回值和当前层的phi(m)比较,确定是否要为结果加上phi(m)。
代码在实现时,使用了pair存储。first位置存储当前结果,second位置存储得到当前结果时,是否出现了超过phi(m)的情况。
其他坑:
1 b=0的情况,答案为1。
2 m=1的情况,答案为0。
3 a=1的情况,答案为1%m。
代码如下

/*
幂塔函数求模运算 
类似题目 https://blog.csdn.net/zzkksunboy/article/details/78867686 
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iomanip>
#define D(x) cout<<#x<<" = "<<x<<"  "
#define E cout<<endl
using namespace std;
typedef long long ll;
typedef pair<ll,int> pii;

ll gcd(ll a,ll b) {
    return !b?a:gcd(b,a%b);
}
ll phi(ll m) {
    int ans=m;
    for(ll i=2; i<=sqrt(m+0.5); i++) {
        if(m%i==0) {
            ans=ans/i*(i-1);
            while(m%i==0) m/=i;
        }
    }
    if(m>1) ans=ans/m*(m-1);
    return ans;
}
pii ksm(ll a,ll b,ll MOD) { //计算a^b%MOD 并判断是否存在结果超出MOD的情况 pair的第二项为0表示存在 
    ll ans=1;
    int flag=1;
    while (b) {
        if (b&1) {
            if ((ans*=a)>=MOD) flag=0;
            ans%=MOD;
        }
        b>>=1;
        if (b) {
            if ((a*=a)>=MOD) flag=0;
            a%=MOD;
        }
    }
    return make_pair(ans,flag);
}
pii solve(ll a,ll b,ll MOD) {
    if (MOD==1) return make_pair(0,0); //模1结果肯定是0 
    if (b==0) { //特判b=0的情况 
        return make_pair(1,0);
    }
    if (b==1) { //b=1为边界 
        if(a<MOD) return make_pair(a%MOD,1);  
        else return make_pair(a%MOD,0);
    }
    pii res=solve(a,b-1,phi(MOD));
    if (gcd(a,MOD)==1) return ksm(a,res.first,MOD); //a和m互质的情况
    //接下来是不互质的情况 
    if (!res.second) res.first+=phi(MOD); 
    return ksm(a,res.first,MOD);
}
int main() {
    //freopen("2.in","r",stdin);
    int T;
    ll a,b,m;
    scanf("%d", &T);
    while(T--) {
        scanf("%lld%lld%lld", &a,&b,&m);
        if(a!=1) printf("%lld\n", (solve(a,b,m).first+m)%m);
        else printf("%lld\n",1%m);
    }
    return 0;
}

https://nanti.jisuanke.com/t/41301
这题和《绿豆蛙的归宿》不同,由于代价中存在到达某个顶点的天数。所以要先沿着DAG进行一次DP,求出到达每个点的期望天数。然后再次进行一次DP,根据期望天数,求出期望的耐久度消耗。(比赛时将天数直接作为dfs的深度或者bfs的层数计算,所以无法跑出样例)
官方题解是如下这么说的。

图片.png

看起来不难,只要分两次做即可。但在实现时,为了让递推方便,需要将dp[u]移项。
我们设到达u点的期望时间为f[u],期望耐久度消耗为g[u]。


化简后得到
同理可得

化简得

注意这里是f[u],不是f[v]。因为我们认为此时处在u点。
如此一来,通过从1号点开始dfs,回溯时计算答案即可(代码中对应method_1)。
但是,这样虽然能算出答案,实际运行结果确时TLE。
原因暂时不清楚。可能是因为dfs会对一些点进行额外访问。
由于是DAG,所以可以用bfs维护拓扑序,做到每个点只访问一次。
但实现时需要对上述转移做修改。
因为bfs时,唯一确定答案的是终点n(f[n]=g[n]=0.0)。所以要建反图,在反图上从n向1进行拓扑序DP。(对应代码中method_2)
这样一来,我们在转移时,对于反图上的边u->v,就需要计算u对v的贡献。
因此我们调整转移方程如下。

化简得

同理

化简得

注意两点
1 关于g数组的递推式中,用到的是f[v]而不是f[u],因为我们认为此时处在v点(因为在算v)。
2 由于是在拓扑排序中计算每个点对后继点的贡献,所以做不到在算完原图中某个点的所有后继点之后追加常数。所以要将贡献项移入中。
代码如下

/*

*/
#define method_2
#ifdef method_1
/*

*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iomanip>
#define D(x) cout<<#x<<" = "<<x<<"  "
#define E cout<<endl
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
const int maxn=100000+5;
const int INF=0x3f3f3f3f;
int n,m,cnt,T,du[maxn],head[maxn];
double f[maxn],g[maxn]; //f[i]表示到i的期望天数 
struct node {
    int from,to;
} edge[maxn*2];
inline void add(int from,int to) {
    edge[++cnt].to=to;
    edge[cnt].from=head[from];
    head[from]=cnt;
}
inline void init() {
    memset(head,0,sizeof(head));
    memset(du,0,sizeof(du));
    cnt=1;
}
inline double dfs1(int x){
    f[x]=0; 
    if(x==n){
        return 0;
    }
    for(int i=head[x]; i; i=edge[i].from){
        int y=edge[i].to;
        f[x]+=dfs1(y)/du[x]; 
    }
    f[x]+=((double)du[x]+1)/du[x];
    return f[x];
}
inline double dfs2(int x){
    g[x]=0;
    if(x==n){
        return 0;
    }
    for(int i=head[x]; i; i=edge[i].from){
        int y=edge[i].to;
        g[x]+=dfs2(y)/du[x]; 
    }
    g[x]+=((double)du[x]+1)/du[x]*f[x];
    return g[x];
}
int main() {
    //freopen("4.in","r",stdin);
    scanf("%d",&T);
    while(T--) {
        init();
        scanf("%d%d",&n,&m);
        int u,v;
        for(int i=1; i<=m; i++) {
            scanf("%d%d",&u,&v);
            add(u,v);
            du[u]++;
        }
        dfs1(1);
        dfs2(1);
        printf("%.2lf\n",g[1]);
    }
    return 0;
}
#endif
#ifdef method_2
/*

*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iomanip>
#define D(x) cout<<#x<<" = "<<x<<"  "
#define E cout<<endl
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
const int maxn=100000+5;
const int INF=0x3f3f3f3f;
int n,m,cnt,T,du[maxn],ru1[maxn],ru2[maxn],head[maxn];
double f[maxn],g[maxn]; //f[i]表示到i的期望天数 
queue<int>q;
struct node {
    int from,to;
} edge[maxn*2];
inline void add(int from,int to) {
    edge[++cnt].to=to;
    edge[cnt].from=head[from];
    head[from]=cnt;
}
inline void init() {
    memset(head,0,sizeof(head));
    memset(du,0,sizeof(du));
    memset(ru1,0,sizeof(ru1));
    memset(ru2,0,sizeof(ru2));
    for(int i=1;i<=n;i++) f[i]=g[i]=0;
    cnt=1;
}
inline void bfs1(){
    while(q.size()) q.pop();
    q.push(n);
    while(q.size()){
        int x=q.front();q.pop();
        for(int i=head[x];i;i=edge[i].from){
            int y=edge[i].to;
            f[y]+=(f[x]+1+(1.0/du[y]))/(du[y]);
            if(--ru1[y]==0) q.push(y);
        }
    }
}
inline void bfs2(){
    while(q.size()) q.pop();
    q.push(n);
    while(q.size()){
        int x=q.front();q.pop();
        for(int i=head[x];i;i=edge[i].from){
            int y=edge[i].to;
            g[y]+=(g[x]+f[y]+(f[y]/du[y]))/(du[y]);
            if(--ru2[y]==0) q.push(y);
        }
    }
}
int main() {
    //freopen("4.in","r",stdin);
    scanf("%d",&T);
    while(T--) {
        init();
        scanf("%d%d",&n,&m);
        int u,v;
        for(int i=1; i<=m; i++) {
            scanf("%d%d",&u,&v);
            add(v,u);
            ru1[u]++,ru2[u]++,du[u]++;
        }
        bfs1();
        bfs2();
        printf("%.2lf\n",g[1]);
    }
    return 0;
}
#endif
#ifdef method_3
/*

*/

#endif
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容

  • 推荐的好题不一定是难题,但往往带有那么一点代表性。凡是由别人推荐的题目,偶会加上推荐人ID和blog地址。偶自己推...
    0222_阅读 1,057评论 0 0
  • 0. 动态规划分析 0.1 动态规划、递归和贪心算法的区别 动态规划就是利用分治思想和解决冗余的办法来处理问题,所...
    dreamsfuture阅读 7,421评论 2 6
  • 整理了校招面试算法题,部分《剑指offer》算法题,以及LeetCode算法题,本博文中算法题均使用Java实现校...
    heyrenly阅读 781评论 0 4
  • 更多干货就在我的个人博客 BlackBlog.tech 欢迎关注!也可以关注我的csdn博客:黑哥的博客谢谢大家!...
    BlackBlog__阅读 6,791评论 0 12
  • 红帐欢 莲心碎影凝春灯, 粉钿萝帐半透红。 一席枕间幽帘醉, 半抹花装悔此生。 昨夜更深露重时, 却挽红...
    北暮无泪阅读 264评论 0 1