2020

今年的题着实令人着迷,(CSP)挂了,(NOIP) 还是要打,本不想碰今年的这个题了,还是拾起了自己摔碎的破烂罐子。

T1 儒略日

利用二分求出年份来,然后就用总天数 (sum)减去到该年的总天数,然后就一个月一个月的减去就行

对于某些特判(就是我犯的):

1. 判断是否为闰年,公元零年没有,也就是公元 1 年, 在(4713≡1()(mod) (p)),所以很坑人的就是(4713 BC)是闰年

2.在判断 1582年的时候,并不是(10)天,而是(11)

代码:

正解:

/*儒略历*/
/*
知识点: 模拟,二分,数论
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
typedef long long ll;
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return x*f;
}
inline ll readll()
{
	ll x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return x*f;
}
int mouth[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
//定义每个月份的天数,闰年的话总天数加上一天就行了
int y=-4713,m=1,d=1;//定义年月日,在每一次询问之前都需要进行初始化
int judge(int y)//判断是否为闰年
{
	if(y<=0)
	{
		y=-y;
		return y%4==1;//这个就很气人
    }
	if(y<=1582) return y%4==0;//如果小于1582那么就是按照儒略日,其他的按照格里高利历
	return (y%400==0)||((y%4==0)&&(y%100!=0));
}
void getday()
{
	d++;
	if(y==1582&&m==10&&d==5)//在1582年凭空消失11天,需要特判一下
	{
		d=15;
	}
	if(d>mouth[m]+(m==2&&judge(y)))//如果今年是闰年,那么二月份为29天
	{
		m++,d=1;//天数已经超过这个月份的天数上限,那么就需要进一个月,是个人就知道
	}
	if(m>12)y++,m=1;//和上面一样
}
//就是注意一下long long
ll checkday(int x)//判断下 以 x年到 BC 4713年的总天数
{
	ll day=1ll*(x+4712)*365;
	if(x>1582)day-=10;
	day+=1ll*(x+4712+3)/4;
	if(x>=1600)
	{
		x-=1601;
		day-=(ll)x/100ll;//100的倍数不是闰年
		day+=(ll)x/400ll;//400的倍数是闰年,上面减多了,(十分类似于2个集合的容斥原理)
	}
	return day;
}
int main()
{
	int T;
	T=read(); 
	while(T--)
	{
		y=0;m=d=1;
		ll n=readll();
		int l=-4712,r=1e9+1;
		while(l<=r)
		{
			int mid=(l+r)/2;
			if(checkday(mid)<=n)//代表mid年到BC 4713年的天数要小于总天数
			{
				y=mid;
				l=mid+1;
			}
			else r=mid-1;
		}
		n-=checkday(y);
		if(y<=0)y--;
		while(n--)getday();
		printf("%d %d ",d,m);
		if(y<=0)printf("%d BC
",-y);
	    else printf("%d
",y);
	}
	return 0;
}

暴力:

#include <algorithm>
#include <cstdio>
#include <cctype>
#include <cstring>
#define LL long long
const int N = 100000 + 10;
const LL D[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
LL d = 1, m = 1, y = -4713;
LL read() {
  LL f = 1, w = 0; char ch = getchar();
  for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = 10 * w + ch - '0';
  return f * w;
}
void SolveBC() 
{
  ++ d;
  if (d > D[m]) {
    if (m == 2 && 
        d == 29 && 
        (- y - 1ll) % 4 == 0) {
      int koishi;
    } else {
      ++ m;
      d = 1;  
    }
  }
  if (m > 12) {
    ++ y;
    m = 1;
  }
  if (y == 0) y = 1;
}
void Solve1() 
{
  ++ d;
  if (d > D[m]) {
    if (m == 2 && 
        d == 29 && 
        y % 4 == 0) {
      int koishi;
    } else {
      ++ m;
      d = 1;  
    }
  }
  if (m > 12) {
    ++ y;
    m = 1;
  }
  
  if (5 == d && m == 10 && y == 1582) {
    d = 15;
  }
}
void Solve2() {
  bool yes = false;
  if (y % 400 == 0) yes = true;
  if (y % 4 == 0 && y % 100 != 0) yes = true;
  ++ d;
  if (d > D[m]) {
    if (m == 2 && d == 29 && yes) {
      int koishi;
    } else {
      ++ m;
      d = 1;  
    }
  }
  if (m > 12) {
    ++ y;
    m = 1;
  }
}
int main() 
{
  int T;
  scanf("%d", &T);
  while (T --) {
    LL r = read();
    {
      d = 1, m = 1, y = -4713;
      while (r --) {
        if (y < 0) SolveBC();
        else if (y <= 1582) Solve1();
        else Solve2();
      }
      if (y < 0) {
        printf("%lld %lld %lld BC
", d, m, -y);
      } else {
        printf("%lld %lld %lld
", d, m, y);
      }
      continue ;
    }
  }
  return 0;
}

T2 动物园

总共有 (2^k)种动物,其中动物园有n种,(动物园(TM)缺动物(?),怎么想的)最后的结果那么肯定就是所有的饲料能够支撑多少种动物(2^x)减去(n)就行了,(啥叫还,我一开始就直接输出了(2^x),开心的暴了5分)

至于怎么求,通过位运算符 (|)来求,先定义一个 f=0,表示现在啥饲料没有(穷死),与动物园的饲料(|)上,然后就得出了动物园种现在的饲料,那么对于要求的时候,就发现,如果(f)的第(p)位为1,那么能饲养这种动物

代码:

/*动物园*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#define int long long
using namespace std;
const int maxn=1e6;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int f=0;
bool vis[maxn];
signed main()
{
	int n=read(),m=read(),c=read(),k=read();
	for(int i=1;i<=n;i++)
	{
		int a=read();
		f=f|a;
	}
	for(int i=1;i<=m;i++)
	{
		int p=read(),q=read();
		if((f|(1ull<<p))!=f && !vis[p] )//表示动物园中需要但是没有这种的饲料
		{
			k--;
			vis[p]=true;
		}
	}
	cout<<"k:"<<k<<endl;
	if(k==64 && n==0) //特判一下,刚好long long溢出个一
	{
	cout<<"18446744073709551616"<<endl;
	return 0;
	}
	unsigned long long ans=(unsigned long long)pow(2,k)-n;
	cout<<ans<<endl;
	return 0;
}

T3 函数调用

待到T4全绿时,便是T3题解日;


T4 贪吃蛇

作为第一道黑题(但是我觉得这就是黑题,未免有些……)

分析一下题意:

有多条在吃(这玩意是真的,蛇真吃同类),然后一回合只能吃一条,那就是最大的吃掉最小的(我就没看题,直接模拟本来20分,然后(0.0)),如果还能吃那么放在下一回合去;

20分做法:

就是判断一下,最长的蛇是否可以吃掉最小的蛇,什么时候不能吃掉,就是不满足题意呗

int main() {
  int T = read();
  for (int nowT = 1; nowT <= T; ++ nowT) {
    if (nowT == 1) {
      n = read();
      for (int i = 1; i <= n; ++ i) {
        ori[i] = a[i] = (Sna) {i, read()};
      }  
    } else {
      int k = read();
      for (int i = 1; i <= k; ++ i) {
        int p = read();
        ori[p].a = read();
      }
      for (int i = 1; i <= n; ++ i) {
        a[i] = ori[i];
      }
    }
    
    int ans = n;
    if (n == 3) 
    {
      if (a[3].a - a[1].a >= a[2].a) {
        ans = 1;
      } else {
        ans = 3;
      }
      printf("%d
", ans);
      continue ;
    }
  }
  return 0;
}

70分做法:

我们直接就认为这些蛇已经冲昏了头脑,如果能吃,它将往死里吃(确实能把自己吃死呀!(QwQ))并且在吃的时候记录一下这里面的蛇的数量,吃完之后,我们让蛇看一下一直吃的结果,都吓坏了,到不能吃的时候,直接就不吃了,同时就是把吃掉导致的结果全部恢复没吃的状态;

这个问题也就是最长的蛇吃掉最短的蛇,同时保证自己不被吃,其他的根本不需要管,上一轮的操作会导致下一轮的回合怎么办,所以,最长的蛇预知未来,该就吃谁,但同时,吃掉蛇后,序列会改变,但是我们要求仍是最长的蛇吃掉最小的蛇,所以我们要(sort)一下,然后就变成了一道光,直到用了multiset才回来。

思路考虑完了,该考虑怎么实现

当蛇的条数((n))等于3的时候,那么此时就是20分的情况,特判一下

当蛇的条数((n))大于等于3的时候,需要一种支持查询最大值,最小值,动态插入删除的数据结构(因为都在疯狂吃,谁管谁大谁小),用平衡树 multiset维护一下

我们去求第一个无法进行的回合,也就是最长的蛇把最小的蛇吃了以后,会被其他长度的蛇吃掉,的时候,这也就是答案

那么怎么去求解第一个无法进行的回合:

站在最长的蛇的角度想,只有它在吃掉最段蛇后的所有回合中 都会不被吃掉,操作才会进行。

这里的所有回合指该回合之后,直到第一个一定不会进行操作的回合。

考虑倒序枚举操作序列,标记所有蛇是否被吃掉,枚举到被删除蛇时判断即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#define int long long
using namespace std;
const int maxn=1e6+10;
struct Snake 
{  
  int val, id;
  bool operator < (const Snake &sec_) const {
    if (val != sec_.val) return sec_.val > val;
    return sec_.id > id;
  }
};
int QwQ,n,opt[maxn],a[maxn];
//QwQ表示的是操作序列的迭代器
// rest[i]表示第i次操作能否成功
bool suc[maxn],del[maxn];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
multiset<Snake> s[11];
void init(int now)//掌管输入大权
{
	QwQ=0;
	memset(del,0,sizeof (del));
	memset(suc,0,sizeof(suc));
	if(now==1)
	{
		n=read();
		for(int i=1;i<=n;i++)
		{
			a[i]=read();
		}
	}
	else 
	{
		int k=read();
		for(int i=1;i<=k;i++)
		{
			int s=read();
			a[s]=read();
		}
	}
}	
void solve(int now_, int lth_) {
  Snake small = *s[now_].begin(), big = *s[now_].rbegin();
  if (s[now_].size() == 3) 
   { 
    multiset <Snake>::iterator it = s[now_].begin();
    ++ it;
    if (big.val - small.val < (*it).val || (big.val - small.val == (*it).val && big.id < (*it).id)) 
      {
      suc[lth_] = false;
    } else {
      suc[lth_] = suc[lth_ + 1] = true;
      opt[++ QwQ] = small.id;
      opt[++ QwQ] = (*it).id;
      del[small.id] = del[(*it).id] = true;
    }
    return ;
  }
  
  s[now_].erase(s[now_].find(big));
  s[now_].erase(s[now_].begin());
  s[now_].insert((Snake) {big.val - small.val, big.id});
  solve(now_, lth_ + 1);
  
  if (!del[big.id]) { 
    suc[lth_] = true;
    opt[++ QwQ] = small.id; 
    del[small.id] = true;
  } else 
   {  
    for (int i = 1; i <= QwQ; ++ i) del[opt[i]] = false;
    QwQ = 0;
  }
}
signed main()
{
	int t=read();
	for(int now=1;now<=t;now++)
	{
		init(now);
		for(int i=1;i<=n;i++)
		{
			s[now].insert((Snake) {a[i],i});
		}
		solve(now,0);
		for(int i=0;i<=n;i++)
		{
			if(!suc[i])
			{
				printf("%d
",n-i);
				break;
			}
		}
	}
	return 0;
}

100分做法:(ちょっと待って)

原文地址:https://www.cnblogs.com/Zmonarch/p/13995587.html