• “蔚来杯“2022牛客暑期多校训练营10


    H.Wheel of Fortune

    题意:
    给出A和它的几个随从的生命值以及B和它的几个随从的生命值。
    每一次会造成10点的伤害,如果最后B<=0,你赢,否则对手赢。
    请输出你赢的概率。

    思路:
    其实我们发现与随从的生命值毫无关系。
    如果A==B,那么双方赢的概率相等,为1/2;
    否则,在这里插入图片描述
    代码:

    #include 
    using namespace std;
    typedef long long ll;
    const int mod = 998244353;
    ll A,B,a[10],b[10];
    
    ll qk(ll a,ll b){
    	ll ans=1;
    	a%=mod;
    	b%=mod;
    	while(b){
    		if(b&1) ans=ans*a%mod;
    		a=a*a%mod;
    		b>>=1;
    		b%=mod;
    	}
    	return ans;
    }
    
    ll inv(ll a){//逆元 
    	return qk(a,mod-2);
    }
    
    
    int main(){
    	scanf("%lld",&A);
    	for(int i=1;i<=7;i++) scanf("%lld",&a[i]);
    	scanf("%lld",&B);
    	for(int i=1;i<=7;i++) scanf("%lld",&b[i]);
    	if(A==B) {
    		printf("499122177\n");
    	}
    	else{
    		ll u=ceil(A/10.0),v=ceil(B/10.0);
    		ll p=inv(qk(2,v)),q=1ll; 
    		ll t=v,tt=2ll;
    		for(ll i=1;i<=u-1;i++){
    			ll num=t*inv(tt)%mod;
    			t=(t*(v+i)%mod*inv(i+1))%mod;
    			tt=tt*2%mod;
    			q=(q+num)%mod;
    		}
    		ll ans=p*q%mod;
    		printf("%lld\n",ans);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    F.Shannon Switching Game?

    题意:
    给出一个可能有重边的图和起点和终点,Join可以删除边u-v并且从u移到v,Cut只能删边,如果Join曾到过t,Join就赢。否则,Cut赢。

    思路:
    等价于问是否有一条从s到t的路径,如果将重边的条数成为边权,那么等价于这条路上的每个边权都要>=2。
    根据博弈论,一个状态是必胜状态当且仅当它至少有一个后继是必败状态。
    将终点t作为必胜态,沿着w>=2的路径走,最后看看w[s]是否>=2,即是否也进入了必胜态集合中。

    代码:

    
    
    #include 
    using namespace std;
    const int N = 10010;
    int n,m,s,t,w[N];
    vector<int> g[N];
    
    void dfs(int u){
    	w[u]++; 
    	if(w[u]!=2) return;//只能沿着至少有2个必胜态的路走 
        for(auto v:g[u]){
        	dfs(v);
    	}
    	
    }
    int main(){
    	int T;
    	scanf("%d",&T);
    	while(T--){
    		scanf("%d%d%d%d",&n,&m,&s,&t);
    		memset(w,0,sizeof(w));
    		for(int i=0;i<=n;i++) g[i].clear();
    		for(int i=1;i<=m;i++){
    			int u,v;
    			scanf("%d%d",&u,&v);
    			g[u].push_back(v);
    			g[v].push_back(u);
    		}
    		w[t]=1;//终点为必胜态,因此初始w[t]=2
    		dfs(t);//从终点/必胜态开始搜素 
    		if(w[s]>=2) puts("Join Player"); 
    		else puts("Cut Player");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    (2)因为无环,所以可以用拓扑排序的逆序来进行,那么每个结点的后继都会被遍历到。
    维护一个队列,先将终点t加入队列,每次选择w==2的点加入队列。

    #include 
    using namespace std;
    const int N = 110;
    int n,m,s,t,w[N];
    vector<int> g[N];
    
    
    int main(){
    	int T;
    	scanf("%d",&T);
    	while(T--){
    		scanf("%d%d%d%d",&n,&m,&s,&t);
    		for(int i=0;i<=n;i++) g[i].clear();
    		memset(w,0,sizeof(w));
    		for(int i=1;i<=m;i++){
    			int u,v;
    			scanf("%d%d",&u,&v);
    			g[u].push_back(v);
    			g[v].push_back(u);
    		}
    	    w[t]=2;
    	    queue<int> q;
    	    q.push(t);
    	    int x,y;
    	    while(!q.empty()){
    	    	x=q.front();
    	    	q.pop();
    	    	for(auto y:g[x]){
    	    		w[y]++;
    	    		if(w[y]==2) q.push(y);
    			}
    		}
    		if(w[s]>=2) puts("Join Player");
    		else puts("Cut Player");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    Yet Another FFT Problem?

    题意:
    给出两个数组a和b,问是否存在|a[i]-a[j]|=|b[k]-b[l]|,如果存在,输出这四个下标。

    思路:
    首先如果原本a数组就存在相等的数字,b数组也存在相等的数字,那么就记录下位置,特判输出。
    否则,就将式子变一下形,变成a[i]+b[l]=a[j]+b[k],如果存在这样的,就输出下标。
    那么在这种情况下,我们需要先对数组进行排序去重,并且在去重之前就对值和对应的下标进行映射,去重之后,记录一下每次的和是否出现过,如果是第一次出现,就记录一下当前这两个数字对应在原数组中的下标。如果之前就已经出现过,就输出之前记录的位置和当前的位置。

    考察;
    容斥原理和鸽巢原理

    注意:
    容易超时,因此用快读进行读入,不能用map进行值和下标的映射,改用数组。

    关于排序和去重:
    unique的功能是去除相邻的重复元素(只保留一个),其实它并不真正把重复的元素删除,是把重复的元素移到后面去了,然后依然保存到了原数组中,然后 返回去重后最后一个元素的地址,因为unique去除的是相邻的重复元素,所以一般用之前都会要排一下序。

        sort(p.begin(),p.end());//排序
    	p.erase(unique(p.begin(),p.end()),p.end());//去重
    
    
    • 1
    • 2
    • 3

    具体见:unique学习笔记

    代码

    #include 
    using namespace std;
    typedef pair PII;
    #define fi first
    #define se second
    #define pb push_back
    const int N = 2e7+10;
    int n,m,a[N],b[N],mpa1[N],mpa2[N],mpb1[N],mpb2[N],w[N];
    int pa1,pa2,pb1,pb2;
    vector p,q;
    
    int read(int &n){
    	char ch=' '; int q=0,w=1;
    	for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    	if(ch=='-')w=-1,ch=getchar();
    	for(;ch>='0'&&ch<='9';ch=getchar())q=q*10+ch-48;
    	n=q*w; return n;
    } 
    
    int main(){
    	read(n),read(m);
    	for(int i=1;i<=n;i++){
    		read(a[i]);
    		if(mpa1[a[i]]){//如果a数组中出现了相同数字 
    			pa1=mpa1[a[i]];//之前这个值的下标 
    			pa2=i;//这个值的当前下标 
    		}
    		else{
    			mpa1[a[i]]=i;//将值与下标进行映射 
    			p.pb(a[i]);//加入到p中 
    		}
    	}
    	for(int i=1;i<=m;i++){
    		read(b[i]);
    		if(mpb1[b[i]]){
    			pb1=mpb1[b[i]];
    			pb2=i;
    		}
    		else{
    			mpb1[b[i]]=i;
    			q.pb(b[i]);
    		}
    	}
    	//排序
    	sort(p.begin(),p.end());
    	sort(q.begin(),q.end());
    	//因为unique是去重的,但是它是把重复的元素移到后面去了,没有真正地去掉
    	//因此这里把后面的重复元素删除 
    	p.erase(unique(p.begin(),p.end()),p.end());
    	q.erase(unique(q.begin(),q.end()),q.end());
    	//如果原本a和b数组中就存在相等的数字,直接输出位置就好了 
    	if(pa1&&pb1){
    		printf("%d %d %d %d\n",pa1,pa2,pb1,pb2);
    		return 0;
    	}
    	//否则就看是否存在ai+bl=aj+bk的,将两个数字的和进行一下映射,看是否出现了两次 
    	for(int i=0;i
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
  • 相关阅读:
    java毕业设计开题报告javaweb敬老院管理系统的设计和实现|养老院
    贝叶斯公式——假阳性问题
    运算符+事件三要素
    保姆级深度学习环境搭建(亲测避坑)
    66从零开始学Java之集合中的Collection体系
    Linux的挖矿木马病毒清除(kswapd0进程)
    线上一次JVM FullGC搞得整晚都没睡,彻底崩溃~
    Redis(10)Geospatial 地理位置
    【App自动化测试】(十三)以雪球财经app为例的移动端自动化测试练习
    java面试题整理《微服务篇》二
  • 原文地址:https://blog.csdn.net/srh20/article/details/126570255