【UOJ Goodbye Jiawu】

A.新年的巧克力棒

这道题我的做法是:如果有2^k个巧克力那么很好算,所以把给定的数字二进制拆分;

2得到1,4得到3,8得到7。。。每一个都是前一位的2倍+1

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
using namespace std;
int main()
{
	int T;
        scanf("%d",&T);
	while (T--)
	{
		int n;
		scanf("%d",&n);
		if (n<=1) puts("0");
		else
		{
			int ans=0,now=1;
			n>>=1;
			while (n)
			{
				if (n&1) ans+=now;
				now=now*2+1;
				n>>=1;
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}

B.新年的毒瘤

很容易得到“毒瘤”的度数一定是m-(n-2),而删去“毒瘤”还能构成一棵树,那么毒瘤一定不是割点。

因此毒瘤的充要条件就是:度数=m-(n-2);不是割点

对于m=n-2的图要特殊处理一下,这种图中一定有一个点是孤立的,而这个点一定是毒瘤

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#define M 100005
using namespace std;
int is[M],tot,v[M],du[M],h[M],low[M],iscut[M],pre[M],dfs_clock=0;
int n,m;
struct Edge
{
	int x,y;
}E[M*2];
struct edge
{
	int y,ne;
}e[M*3];
bool ok=false;
int cnt=0;
void Addedge(int x,int y)
{
	e[++tot].y=y;
	e[tot].ne=h[x];
	h[x]=tot;
}
void tarjan(int u,int fa)
{
	low[u]=pre[u]=++dfs_clock;
	int child=0;
	for (int i=h[u];i;i=e[i].ne)
	{
		int v=e[i].y;
		if (!pre[v])
		{
			child++;
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
			if (low[v]>=pre[u])
				iscut[u]=1;
		}
		else if (pre[v]<pre[u]&&v!=fa)
			low[u]=min(low[u],pre[v]);
	}
	if (fa==0&&child==1) iscut[u]=0;
}
int main()
{
        scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		Addedge(x,y),Addedge(y,x);
		E[i].x=x,E[i].y=y;
		du[x]++,du[y]++;
	}
	if (m==n-1)
	{
		int cnt=0;
		for (int i=1;i<=n;i++)
			if (du[i]==1) cnt++,is[i]=1;
		cout<<cnt<<endl;
		for (int i=1;i<=n;i++)
			if (is[i]) cout<<i<<" ";
		cout<<endl;
		return 0;
	}
	if (m==n-2)
	{
		for (int i=1;i<=m;i++)
			is[E[i].x]=1,is[E[i].y]=1;
		cout<<1<<endl;
		for (int i=1;i<=n;i++)
			if (!is[i]) cout<<i<<endl;
		return 0;
	}
	tarjan(1,0);
	for (int i=1;i<=n;i++)
		if (!iscut[i]&&m-du[i]==n-2) cnt++,is[i]=1;
        cout<<cnt<<endl;
	for (int i=1;i<=n;i++)
		if (is[i]) cout<<i<<" ";
	cout<<endl;
	return 0;
}

C.新年的桌游

分类讨论。。

1.对于红太狼,有多少肯定就直接都出了

2.对于美羊羊,先判断能否通过她取得胜利,如果能,就直接出了;如果不能,她也并不是一无是处,可以作为对方出灰太狼的“威胁”,使得对方一直保持手里的灰太狼多于自己(让对方不敢出太多灰太狼)

3.接下来就是考虑灰太狼和喜羊羊了:计算双方获胜所需的最小局数,取一个较小的就是胜者(注意要考虑美羊羊的威胁)

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#define inf 0x3f3f3f3f
using namespace std;
int a[5],b[5];
void D()
{
	puts("Draw");
}
void X()
{
	puts("Xiyangyang");
}
void M()
{
	puts("Meiyangyang");
}
int main()
{
	int T;
        scanf("%d",&T);
	while (T--)
	{
		for (int i=1;i<=4;i++)
			cin>>a[i];
		for (int i=1;i<=4;i++)
			cin>>b[i];
		b[1]-=a[3],a[3]=0;  //先手的红太狼
		if (b[1]<0)
		{
			M();continue;
		}
		if (a[4]&&a[1]>=b[1]) //先手的美羊羊
		{
			M();continue;
		}
		if (a[1]&&!b[2])
		{
			M();continue;
		}
		a[1]-=b[3],b[3]=0;  //后手的红太狼
		if (a[1]<0)
		{
			X();continue;
		}
		if (b[4]&&b[1]>=a[1]) //后手的美羊羊
		{
			X();continue;
		}
		int x=inf,y=inf;
                if ((!b[4]&&a[1]>b[2])||(b[4]&&a[1]>b[1]+b[2]))
			x=b[2]+1;
		if ((!a[4]&&b[1]>a[2])||(a[4]&&b[1]>a[1]+a[2]))
			y=a[2]+1;
		if (x==inf&&y==inf) D();
		else if (x<=y)
		{
			if (b[1]>=x-1&&x-1>a[2]) D();
			else M();
		}
		else
		{
			if (a[1]<=b[1]+1&&a[1]>=y-1&&y-1>b[2]) D();
			else if (a[1]>b[1]+1&&a[1]>=y&&y>b[2]) D();
			else X();
		}
	}
	return 0;
}

D.新年的QAQ

我做了70分的点,先判断n是几,然后输出答案。判断n是几的方法是从0枚举到16看n与哪个相同。为了避免判断相同的误差,我的做法是:

如果判断相等,那么再次判断是否相等,如果还相等,再判断是否相等;如果不相等,从头开始判断。

如果判断不相等,那么再次判断是否不相等,如果还不相等,再判断是否不相等;如果相等,从头开始判断。

这样经过几轮(我进行了4轮)之后,如果每次判断都是一样的,那么这个判断基本可以保证是正确的。

下面是一个程序生成器。

#include <iostream>
#include <cstdio>
#include <iostream>
using namespace std;
int f[100];
int main()
{
	freopen("t.out","w",stdout);
	f[0]=0,f[1]=1;
	for (int i=0;i<=16;i++)
	{
		printf("a = %d",i);cout<<"\\n";
		printf("b = a == n");cout<<"\\n";
		printf("if b goto %d",72+i*3);cout<<"\\n"; //去是
		printf("if e goto %d\\n",123+i*3); //去否
	}
  	//1
        for (int i=0;i<=16;i++)
	{
		printf("b = a == n\\n");
		printf("if b goto %d\\n",174+i*3);  //去是
		printf("if e goto %d\\n",4+4*i);  //返回再次判断当前数字
	}
	for (int i=0;i<=16;i++)
	{
		printf("b = a == n\\n");
		printf("if b goto %d\\n",4+4*i);  //返回再次判断当前数字
		printf("if e goto %d\\n",225+i*3);  //去否
	}
	//2
        for (int i=0;i<=16;i++)
	{
		printf("b = a == n\\n");
		printf("if b goto %d\\n",276+i*3);  //去是
		printf("if e goto %d\\n",4+4*i);  //返回再次判断当前数字
	}
	for (int i=0;i<=16;i++)
	{
		printf("b = a == n\\n");
		printf("if b goto %d\\n",4+4*i);  //返回再次判断当前数字
		printf("if e goto %d\\n",327+i*3);  //去否
	}
	//3
        for (int i=0;i<=16;i++)
	{
		printf("b = a == n\\n");
		printf("if b goto %d\\n",378+i*3);  //去是
		printf("if e goto %d\\n",4+4*i);  //返回再次判断当前数字
	}
	for (int i=0;i<=16;i++)
	{
		printf("b = a == n\\n");
		printf("if b goto %d\\n",4+4*i);  //返回再次判断当前数字
		printf("if e goto %d\\n",429+i*3);  //去否
	}
        //4
	for (int i=0;i<=16;i++)
	{
		printf("b = a == n\\n");
		printf("if b goto %d\\n",480+i*3);  //输出
		printf("if e goto %d\\n",4+4*i);  //返回再次判断当前数字
	}
	for (int i=0;i<=16;i++)
	{
		printf("b = a == n\\n");
		printf("if b goto %d\\n",4+4*i);  //返回再次判断当前数字
		printf("if e goto %d\\n",4+4*(i+1));  //返回继续判断下一个数字
	}
        for (int i=0;i<=16;i++)
	{
		if (i>1) f[i]=f[i-1]+f[i-2];
		printf("a = %d",f[i]);cout<<"\\n";
		printf("output a");cout<<"\\n";
		cout<<"if e goto 100000\\n";
	}
	return 0;
}

感悟:

考的不能更烂了,第二题竟然求了边双。。第三题分类讨论写挂。。

还是太弱了,认真刷题吧。。。

如果要输出“\n”,先加一个"\"才能输出。

时间: 2024-10-21 11:07:19

【UOJ Goodbye Jiawu】的相关文章

【UOJ Round #3】

枚举/二分 C题太神窝看不懂…… 核聚变反应强度 QwQ很容易发现次小的公约数一定是gcd的一个约数,然后……我就傻逼地去每次算出a[1],a[i]的gcd,然后枚举约数……这复杂度……哦呵呵... 正解是先找到a[1]的所有质因数啊……然后在刚刚那个算法的“枚举gcd的约数”的时候直接枚举这些质因数就好了…… 1 //UOJ Round3 A 2 #include<vector> 3 #include<cstdio> 4 #include<cstring> 5 #in

【UOJ Round #1】

枚举/DP+排列组合 缩进优化 QAQ我当时一直在想:$min\{ \sum_{i=1}^n (\lfloor\frac{a[i]}{x}\rfloor + a[i] \ mod\ x) \}$ 然而并不会做啊……一点思路也没有……主要是后面那个取模非常难受…… 其实正解有点逆向思维的感觉:$ans=\sum_{i=1}^n a[i] - max\{ \sum_{i=1}^n \lfloor \frac{a[i]}{x}\rfloor *(x-1) \} $ 也就是先将a[i]全部加起来,然后再

【UOJ Round #8】

A 一道不错的题,虽然大家都觉得是水题,然而蒟蒻我想出来的好慢……Orz alpq 发现其实就是一个网格图,每一个大块都是同一颜色……横纵坐标互不干扰…… 1 //UOJ Round #8 A 2 #include<vector> 3 #include<cstdio> 4 #include<cstring> 5 #include<cstdlib> 6 #include<iostream> 7 #include<algorithm> 8

【uoj#37/bzoj3812】[清华集训2014]主旋律 状压dp+容斥原理

题目描述 求一张有向图的强连通生成子图的数目对 $10^9+7$ 取模的结果. 题解 状压dp+容斥原理 设 $f[i]$ 表示点集 $i$ 强连通生成子图的数目,容易想到使用总方案数 $2^{sum[i]}$ 减去不为强连通图的方案数得到强连通图的方案数,其中 $sum[i]$ 表示点集 $i$ 中边的数目. 考虑什么样的图不是强连通图:缩点后入度为0的强连通分量对应的点集不是全集. 枚举这些入度为0的强连通分量对应的点集,由于无法保证只有这些点构成的入度为0的强连通分量,因此需要进一步容斥.

【UOJ】【UR #2】猪猪侠再战括号序列(splay/贪心)

http://uoj.ac/problem/31 纪念伟大的没有调出来的splay... 竟然那个find那里写错了!!!!!!!!!!!!! 以后要记住:一定要好好想过! (正解的话我就不写了,太简单了.. #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> #

uoj 41 【清华集训2014】矩阵变换 婚姻稳定问题

[清华集训2014]矩阵变换 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/41 Description 给出一个 N 行 M 列的矩阵A, 保证满足以下性质: M>N.    矩阵中每个数都是 [0,N] 中的自然数.    每行中, [1,N] 中每个自然数都恰好出现一次.这意味着每行中 0 恰好出现 M−N 次.    每列中,[1,N] 中每个自然数至多出现一次. 现在我们要在每行中选取一个非零数,

【UOJ#67】新年的毒瘤(Tarjan)

[UOJ#67]新年的毒瘤(Tarjan) 题面 UOJ 题解 一棵\(n\)个节点的树显然有\(n-1\)条边,在本题中意味着删去一个点之后还剩下\(n-2\)条边.那么找到所有度数为\(m-(n-2)\)的点就好了.但是因为是一棵树,所以联通,所以割点不是答案. #include<iostream> #include<cstdio> using namespace std; #define ll long long #define MAX 100100 inline int r

【UOJ#246】套路(动态规划)

[UOJ#246]套路(动态规划) 题面 UOJ 题解 假如答案的选择的区间长度很小,我们可以做一个暴力\(dp\)计算\(s(l,r)\),即\(s(l,r)=min(s(l+1,r),s(l,r-1),abs(a_r-a_l))\). 我们发现\(s(l,r)\le \frac{m}{r-l+1}\),那么当长度足够大的时候\(s(l,r)\)的取值很小. 所以我们对于询问分治处理,当长度小于\(\sqrt m\)时,直接\(dp\)计算贡献. 否则,当长度大于\(\sqrt m\)时,枚举

【UOJ#22】【UR #1】外星人(动态规划)

[UOJ#22][UR #1]外星人(动态规划) 题面 UOJ 题解 一道简单题? 不难发现只有按照从大往小排序的顺序选择的才有意义,否则先选择一个小数再去模一个大数是没有意义的. 设\(f[i][j]\)表示考虑了前\(i\)个数,模完之后是\(j\)的方案数. 转移的时候枚举这个数是模还是不模,如果不模的话就要把它放到后面某个小数的后面,方案数是\(n-i\). #include<iostream> #include<cstdio> #include<cstdlib>