dut周赛第一周

没午睡头昏脑胀把能踩的坑都踩了....签到题都没写完(读题和代码能力一直是短板ORZ)

EFG比较水,有人有需求再添加,这里只给代码。J(已补) SG函数还不会...得找个时间学(潼神每次都出SG函数 蓝瘦)。

 

E:判断C的情况  大于10000遍历c的倍数  ,小于10000因为 位数平方和最多9*81  所以遍历c*81*9

    	    			
    #include<bits/stdc++.h>
using namespace std;

int bb(long long g){
	int now=0;
	while(g>0)
	{
		int tmp=g%10;
		now+=tmp*tmp;
		g/=10;
	}
	return now;
}

int main()
{
	long long a,b,c;int ans=0;
	scanf("%lld%lld%lld",&a,&b,&c);
	if(c>10000){
		for(int i=1;(i-1)*c<=b;i++)
		{
			if(bb(i*c)==i&&(i*c>=a)&&(i*c<=b)){
				ans++;
			}
		}
		printf("%d\n",ans);
		return 0;
	}
	long long maxx=81*9*(c+1);
	for(int i=1;i<=maxx;i++)
	{
			if(bb(i)*c==i&&i>=a&&i<=b){
				ans++;
			}
	}
	printf("%d\n",ans);
	
}		
    

F:赢x次的概率(x<12则最后一场一输结束)C(x+2,2)*p^x*(1-p)^3  赢12次以此类推。

    	    			
    #include<bits/stdc++.h>
using namespace std;
		double p;
int cc(int a,int b)
{
	int ans=1;
	for(int i=0;i<b;i++)
	{
		ans*=a-i;
	}
	for(int i=1;i<=b;i++)
	{
		ans/=i;
	}
	return ans;
}
int main()
{

		scanf("%lf",&p);double ans=0;//printf("~%d\n",cc(5,2));
		for(int i=0;i<=11;i++)
		{
			double gg=1;
			double ggg=(1-p)*(1-p)*(1-p);
			for(int j=0;j<i;j++)
			{
				gg*=p;
			}
			ans+=i*cc(i+2,2)*gg*ggg;//printf("%d %d %lf\n",i,cc(i+2,2),ans);
		}
			double gg=1;
			double ggg=(1-p)*(1-p);
			for(int j=0;j<12;j++)
			{
				gg*=p;
			}
			
			ans+=12*cc(12,1)*gg*(1-p);
			ans+=12*cc(13,2)*gg*(1-p)*(1-p);
		//	ans+=12*cc(14,2)*gg*(1-p)*(1-p)*(1-p);
			
			ans+=12*gg;
			printf("%lf",ans);
}		
    

G:维护小于等于L1的最远点和小于等于L2的最远点和小于等于L3的最远点 然后求飞这三个点的最小值

    #include<bits/stdc++.h>
using namespace std;
int ll[10010];
int aa[10010];
int minans[10010];
    int l1,l2,l3,c1,c2,c3;
    int n;
int money(int len)
{
    if(len<=l1) return c1;
    if(len<=l2) return c2;
    if(len<=l3) return c3;
    else return 99999999;
}
int main()
{
 
    scanf("%d%d%d%d%d%d",&l1,&l2,&l3,&c1,&c2,&c3);
    scanf("%d",&n);
    int a,b;
    scanf("%d%d",&a,&b);
    int st,en;
    for(int i=2;i<=n;i++)
    {
        scanf("%d",&aa[i]);
        if(i==a) st=aa[i];
        if(i==b) en=aa[i];
    }
    int n1,n2,n3;
    n1=n2=n3=a;
    for(int i=a+1;i<=b;i++)
    {
        while(aa[i]-aa[n1]>l1&&n1<i-1){
            n1++;
        }
        while(aa[i]-aa[n2]>l2&&n2<i-1){
            n2++;
        }
        while(aa[i]-aa[n3]>l3&&n3<i-1){
            n3++;
        }
        minans[i]=min(minans[n1]+money(aa[i]-aa[n1]),minans[n2]+money(aa[i]-aa[n2]));
        minans[i]=min(minans[i],minans[n3]+money(aa[i]-aa[n3]));
    }
    printf("%d\n",minans[b]);
}

H:

1234: Zeratul与塔防游戏

Time Limit:4000/2000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:39   Accepted:6

[Submit][Status][Discuss]

Description

Zeratul有n(1≤n≤10000)n(1≤n≤10000)座防御塔,每个防御塔覆盖[L[i],R[i]][L[i],R[i]],且攻击力为A[i](1≤A[i]≤1000)A[i](1≤A[i]≤1000)。区间[1,m](1≤m≤10000)[1,m](1≤m≤10000)上每个整点有一个防御值,是所有能覆盖到这个点的防御塔的攻击力之和。Zeratul可以给防御塔升级k(0≤k≤109)k(0≤k≤109)次,每次升级可以将一个防御塔的攻击力提高1。同一个防御塔可以被多次升级。

现在Zeratul想知道,[1,m][1,m]上所有整点的最小防御值最大是多少。

 

Input

第一行包括三个整数n,m,kn,m,k,含义见Description。

接下来n行,每行包括三个整数L[i],R[i],A[i](1≤L[i]≤R[i]≤m)L[i],R[i],A[i](1≤L[i]≤R[i]≤m),代表第ii座防御塔的覆盖范围和第ii座防御塔的攻击力。

Output

 一个整数,代表最小的防御值最大是多少。

Sample Input

3 5 3
1 4 5
2 5 1
3 4 1

Sample Output

4

HINT

 

 Sample需要将第2座防御塔加强三次。

 

Source

Zeratul

题解:基本上是2018徐州的H的加强版,二分答案 每个答案从左到右判断每个区间  如果区间攻击值总和小于ans就把包括当前点同时右端点最靠右的区间补到总和为ans为止  包含区间右端点最大值用单调队列维护即可,结构体用法比较奇葩,因为当时徐州就是这么写的ORZ 复杂度o(nlogn)代码有注释。

#include<bits/stdc++.h>
using namespace std;
int n,m,k;

struct node{
	int num;
	int lr;
}no[20020];
int zone[10010][2];//每个区间长度 
int a[10010];//每个区间初始值 
int q[20020];//优先队列 
int sum[20020];//每个区间的等级 
void init()
{
	for(int i=0;i<=n;i++) sum[i]=a[i];
}
int check(int ans)
{
	init();int head=1;int tail=0;
	int nowd=0;//nowd是当前整点的防御值 
	if(ans==0) return 1;
	if(zone[no[1].num][no[1].lr]!=1||zone[no[2*n].num][no[2*n].lr]!=m+1) return 0; //特判一下区间范围有没有包含1和m 删除也能过 
	int use=0;//use表示使用的升级点数 
	for(int i=1;i<=2*n;i++)
	{
		if(no[i].lr==1)//假如是右端点 
		{	
		nowd-=sum[no[i].num];	//剪掉当前区间提供的防御值 
				if(nowd<ans&&zone[no[i].num][1]<=m)//如果剪完后当前节点防御值不到ans 
				{			
					if(zone[q[head]][1]<=zone[no[i].num][no[i].lr])//单调队列 到当前位置前包含的所有区间右端点最大值小于等于当前节点 则无法将此节点增加到ans 
					{
						return 0;
					}
					else{
						sum[q[head]]+=ans-nowd;use+=ans-nowd;nowd=ans;
						if(use>k) return 0;//如果升级点数超过k 
					}
				}					
		}
		if(no[i].lr==0)//如果是左端点 
		{
				nowd+=sum[no[i].num];//加上该区间点数 
			if(head>tail)// 将该区间推入维护右端点最大值的优先队列 
			{
				tail++;q[tail]=no[i].num;
			}
			else{
				while(head<=tail&&zone[no[i].num][1]>=zone[q[tail]][1]){
					tail--;
				}
				tail++;q[tail]=no[i].num;
			}
			if(zone[no[i].num][no[i].lr]!=zone[no[i+1].num][no[i+1].lr])//如果 下一个节点和当前节点位置不同,则应增加该节点的值到ans 
			{
				if(nowd<ans)
				{			
					if(zone[q[head]][1]<=zone[no[i].num][no[i].lr])//如果单调队列队首 (到当前位置前包含的所有区间右端点最大值)小于等于当前节点 则无法将此节点增加到ans 
					{
						return 0;
					}
					else{
						sum[q[head]]+=ans-nowd;use+=ans-nowd;nowd=ans;
						if(use>k) return 0;//如果升级点数超过k 
					}
				}
			}
		}
	}
	return 1;
	
}
int find() //二分答案 
{
    int left = 0;
    int right = k+2000-1;
    while (left <= right) {
        int mid = (left + right) / 2;
        if ((check(mid)^1)>=1) {
            right = mid - 1;
        }
        else {
            left = mid + 1;
        }
    }
    return right;
}
int cmp(node a,node b)//将区间左右端点排序 
{
	if(zone[a.num][a.lr]!=zone[b.num][b.lr])//先按位置大小排序 
	{
		return zone[a.num][a.lr]<zone[b.num][b.lr];
	}
	if(a.lr!=b.lr)//相同位置左端点在前右端点在后 
	{
		return a.lr<b.lr;
	}
	else//相同位置左端点按右端点大小从大到小排 
	{
		return zone[a.num][1]>zone[b.num][1];
	}
}
int main()
{
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d%d",&zone[i][0],&zone[i][1],&a[i]);
		zone[i][1]++;//右端点+1 方便处理 
		no[i*2-1].lr=0;no[i*2-1].num=i;
		no[i*2].lr=1;no[i*2].num=i;
	}
	sort(no+1,no+1+2*n,cmp);
	printf("%d\n",find());
}

 

I:

1235: Zeratul与Kerrigan的情报战

Time Limit:4000/2000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:10   Accepted:3

[Submit][Status][Discuss]

Description

Kerrigan在编号为11到n(1≤n≤105)n(1≤n≤105)的星球都分别部署有一些兵力,每个星球的兵力都可以用一个非负整数来表示。这些军队正在准备进攻Protoss的领地。

现在Zeratul得到了一些关于Kerrigan军事行动的情报。Zeratul得到的情报是下面这个形式的:三个整数L,R,V(1≤L≤R≤n,0≤V≤(231−1))L,R,V(1≤L≤R≤n,0≤V≤(231−1)),代表Kerrigan在编号为LL到编号为RR的星球上的兵力的异或为VV。

现在Zeratul想要知道,他可以从这些情报中确定出多少个星球的具体兵力。如果情报是自相矛盾的,输出-1。

 

Input

第一行包括两个整数n,m(1≤m≤100000)n,m(1≤m≤100000),分别代表星球的个数和情报的个数。

接下来m行,每行包括三个整数L,R,V,含义见Description。

Output

一个整数,代表Zeratul可以确定出多少个星球的具体兵力。如果情报出现矛盾,输出-1。

Sample Input

10 3
1 10 7
1 5 4
7 10 1

Sample Output

1

HINT

 

Sample中情报没有出现矛盾,并且Zeratul可以确定6号星球的兵力一定是2。其他星球的兵力均无法确定。

 

Source

Zeratul

[Submit][Status][Web Board]

题解:

经典的权值并查集题  只不过把就和改成求异或和,而且异或优先级比不等于低!!所以不加括号很难查到错在哪里ORZ

代码:

    	    			
    #include <cstdio>

const int maxn = 100000 + 10;

int pre[maxn];
int sum[maxn];    // sum是该节点到其根的异或和,比如说sum[3],前三个的前缀异或和到根 
int find(int x) {
    if (x == pre[x])  return x;
    else {
        int root = find(pre[x]);     // 找到根节点
        sum[x] ^= sum[pre[x]];       // 权值合并,更新
        return pre[x] = root;        // 压缩路径
    }
}
int know[100010];
int main() {
    int n, m;
    scanf("%d%d", &n, &m);
        for(int i = 0; i <= n; i++) {
            pre[i] = i;
            sum[i] = 0;
        }
        int x, y;
        int s;
        int ans = 0;
        while(m--) {
            scanf("%d%d%d", &x, &y, &s);
            x--;        //表示前x-1个数的前缀异或和 与 前y个数异或和 的关系 
            int fx = find(x);
            int fy = find(y);
            if (fx != fy) {
                pre[fy] = fx;
                sum[fy] = sum[x] ^ sum[y] ^ s;
            }
            else if ((sum[y] ^ sum[x] )!= s)//!!!这里^优先级小于!=  所以用和的来改不加括号只能疯狂哇QAQ 
			{
            	printf("-1\n");return 0;
            }

        }

        for(int i=0;i<n;i++)
        {
        	if(find(i)==find(i+1))
        	{
        		ans++;
        	
			}
		}
        printf("%d\n", ans);
    
    return 0;
}
/*
4 4
1 2 1
2 3 2
1 3 1
2 2 1
*/		
    

 

1233: Mario与Luigi的组合游戏

Time Limit:3000/1000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:7   Accepted:3

[Submit][Status][Discuss]

Description

Zeratul首发购买了Nintendo Switch上Mario Party,但由于身边玩Switch的人实在是太少了,这款游戏只能躲在角落吃灰。

Mario与Luigi是三十年前就有的老组合了。他们现在正在玩一种游戏:

桌面上有n(1≤n≤105)n(1≤n≤105)堆石子,每堆石子的个数为a[i](1≤a[i]≤109)a[i](1≤a[i]≤109)。Mario与Luigi交替进行操作,操作可以从以下两种中任选其一:

1.从某堆石子中拿走一个石子。

2.拿走某堆个数为偶数的石子,并且将m(1≤m≤109)m(1≤m≤109)堆石子放回桌面上。放回桌面上的mm堆石子中,每堆的石子个数都为拿走石子数的一半。

Mario会先手进行操作,如果轮到某人操作时,桌面上已经没有石子,那么这个人就输了。

Zeratul意识到,这显然是一种组合游戏,必定有一方存在必胜策略。你的任务是计算当两人都采用最优策略时,谁会取得胜利。

 

Input

输入第一行包括两个整数n,mn,m,含义见Description。

第二行包括nn个整数,代表a[1...n]a[1...n]。

 

Output

如果Mario会取得胜利,输出“Mario”,否则输出“Luigi”。

 

Sample Input

5 1
1 2 3 4 5

Sample Output

Mario

HINT

 

Source

Zeratul

SG函数学习->

题解:没学过SG函数的可以先去看看,学过的话就是一题水题。显然m是偶数的话偶数SG值除了SG[2]是2其他都是1。

如果m是奇数因为只有拿走一个棋子和偶数拆成m堆两种情况, 前几个打下表,后面的偶数可以logn判断,奇数显然是0. 直接暴力求SG值复杂度O(nlogn)刚刚好

代码:

#include<bits/stdc++.h>
using namespace std;
int a[100010];
int sg[2][20];	int n,m;
int SG(int now){
	if(m%2==0){
		if(now<=6){
			return sg[0][now];
		}
		else{
			return (now+1)%2;
		}
	}
	else{
		if(now<=6){
			return sg[1][now];
		}
		else{
			if(now&1){
				return 0;
			}
			else{
				int bb[3];bb[0]=bb[1]=bb[2]=0;
				bb[SG(now/2)]++;
				for(int i=1;i<=2;i++){
					if(!bb[i]) return i;
				}
			}
		}
	}
	
}
int main()
{
	sg[0][1]=1,sg[0][2]=2,sg[0][3]=0,sg[0][4]=1,sg[0][5]=0,sg[0][6]=1;
	sg[1][1]=1,sg[1][2]=0,sg[1][3]=1,sg[1][4]=2,sg[1][5]=0,sg[1][6]=2;
	scanf("%d%d",&n,&m);int ans=0;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		ans^=SG(a[i]);
	}
	if(ans){
		printf("Mario\n");
	}
	else{
		printf("Luigi\n");
	}
 } 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值