ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

NOIP模拟64

2021-10-01 20:00:50  阅读:146  来源: 互联网

标签:ch NOIP int long dep 64 ull 模拟 define


T1 三元组

解题思路

一看题面,好像是一道数学题,但不完全是,或者说根本不是。。。

比较好想到的是 \(\mathcal{O}(n^2)\) 和 \(\mathcal{O}(nk)\) 的做法,然后就有了 60pts。。。

观察范围对于每一个 \(b\) 而言 \(a+b^2\) 的范围就是 \([1+b^2,b+b^2]\) 。

充分利用 \(a\le b\le c\) 这个条件,枚举 \(c\) 然后就对于每一个新加入的 \(c\) , \(a,b\) 的范围也会相应的扩大。

因此可以维护树状数组,对于取模之后的区间进行区间修改,然后单点查询每一个 \(c^3\) 的贡献就好了。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int N=1e5+10;
int Test,ans,n,p;
struct BIT
{
	int tre[N];
	void clear(){memset(tre,0,sizeof(tre));}
	int lowbit(int x){return x&(-x);}
	void insert(int x,int val){for(int i=x+1;i<=p;i+=lowbit(i))tre[i]+=val;}
	int query(int x){int sum=0;for(int i=x+1;i;i-=lowbit(i))sum+=tre[i];return sum;}
	void insert(int l,int r,int val){insert(l,val);insert(r+1,-val);}
}T;
void solve()
{
	n=read(); p=read(); ans=0; T.clear();
	for(int i=1;i<=n;i++)
	{
		int l=(1+i*i)%p,r=(i+i*i)%p,temp=i/p;
		T.insert(0,p-1,temp);
		if(i%p&&l<=r) T.insert(l,r,1);
		else if(i%p&&l>r) T.insert(l,p-1,1),T.insert(0,r,1); 
		ans+=T.query(i*i*i%p);
	}
	printf("%lld\n",ans);
}
signed main()
{
	freopen("exclaim.in","r",stdin); freopen("exclaim.out","w",stdout);
	Test=read(); for(int i=1;i<=Test;i++) printf("Case %lld: ",i),solve();
	return 0;
}

T2 简单的字符串

解题思路

打了一种假做法,但是好像不是特别可以被卡掉(吸氧的前提下)

\(n^3\) 的做法加上字符集优化(也就是无序 Hash 即可)。

当然为了防止被 Hack ,于是我加了一个 map 记忆化一下

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int N=5e3+10;
const ull base=133331ull;
int n,ans,s[N];
ull has,has2,hs[N],p[N],pre[N];
map< pair<ull,ull> , bool > mp;
ull power(ull x,int y)
{ull temp=1;while(y){if(y&1) temp=temp*x;x=x*x; y>>=1;}return temp;}
ull get(int l,int r){return pre[r]-pre[l-1]*p[r-l+1];}
signed main()
{
	freopen("s.in","r",stdin); freopen("s.out","w",stdout);
	n=read(); p[0]=1;
	for(int i=1;i<=n;i++)
		s[i]=read(),pre[i]=pre[i-1]*base+s[i],
		p[i]=p[i-1]*base,hs[i]=hs[i-1]+power(s[i],base);
	for(int len=2;len<=n;len+=2)
		for(int l=1;l+len-1<=n;l++)
		{
			int r=l+len-1,mid=(l+r)>>1; has=pre[r]-pre[mid]*p[len/2]; has2=pre[mid]-pre[l-1]*p[len/2];
			if(hs[r]-hs[mid]!=hs[mid]-hs[l-1]) continue;
			if(has==has2||mp.find(make_pair(has,has2))!=mp.end()){ans++;continue;}
			for(int i=l;i<=mid;i++)
			{
				ull ha1=get(l,i),ha2=get(i+1,mid),ha=ha1+ha2*p[i-l+1];
				if(has==ha)
					{
						if(has>has2) swap(has,has2);
						mp.insert(make_pair(make_pair(has,has2),true));
						ans++;break;
					}
			}
		}
	printf("%lld",ans);
	return 0;
}

T3 环路

解题思路

矩阵快速幂

矩阵 \(A_{i,j}\) 表示 i 到 j 是否有连边,也就是初始读入的矩阵, B 为单位矩阵。

于是我们就可以快速利用矩阵快速幂算出每个点在 k 步可以到达的点,但是这样显然需要记录到每一个状态的答案。

考虑建假点,对于 \(i\) 点建一个 \(i+n\) 作为假点,每个点向相对应的假点连一条边,同样的假点也要向自己连边。

最后答案就是 从 \(i\) 到 \(i+n\) 的方案数减去 \(n\) 也就是没有移动的方案数

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int N=210;
int n,m,mod,ans;
char ch[N];
struct Square
{
	int a[N][N];
	void clear(){memset(a,0,sizeof(a));}
	Square friend operator * (Square x,Square y)
	{
		Square z; z.clear();
		for(int i=1;i<=2*n;i++)
			for(int j=1;j<=2*n;j++)
				for(int k=1;k<=2*n;k++)
					z.a[i][j]+=x.a[i][k]*y.a[k][j]%mod;
		for(int i=1;i<=2*n;i++)
			for(int j=1;j<=2*n;j++)
				z.a[i][j]%=mod;
		return z;
	}
}A,B;
void power(Square &x,Square e,int y){while(y){if(y&1)x=x*e;e=e*e;y>>=1;}}
signed main()
{
	freopen("tour.in","r",stdin); freopen("tour.out","w",stdout);
	n=read();
	for(int i=1;i<=n;i++)
	{
		scanf("%s",ch+1); B.a[i][i]=B.a[i+n][i+n]=A.a[i][i+n]=A.a[i+n][i+n]=1;
		for(int j=1;j<=n;j++) A.a[i][j]=(ch[j]=='Y');
	}
	m=read(); mod=read(); power(B,A,m);
	for(int i=1;i<=n;i++) ans+=B.a[i][i+n];
	printf("%lld",(ans-n+mod)%mod);
	return 0;
}

T4 过河

解题思路

很玄学的一道题,从考试开始到结束看这个题的思路只有 模拟,模拟,再模拟,然后喜提 0pts

对于 60pts 的做法直接暴力枚举在运送神猪(就是所有三元组都有的猪)前后所运送的两只猪判断剩下的关系是否是二分图就好了。

进行一些优化只枚举一只,查看剩下的图是否可以通过删掉一个点成为二分图。

因此我们可以高出一个 DFS 树,一个合法的点的充要条件就是被所有奇数长度的环经过,并且不可以存在一个奇数环或者偶数环一段在子树中,另一端在当前点的上方。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int N=3e3+10,INF=1e18;
int T,n,m,jud,flag,pos,all,dep[N],fa[N],odd[N],even[N],minn[N];
int tot=1,head[N],nxt[N<<1],ver[N<<1];
bool vis[N];
bitset<N> bit;
struct Node{int a,b,c;}s[N];
void add_edge(int x,int y)
{
	ver[++tot]=y;
	nxt[tot]=head[x];
	head[x]=tot;
}
void dfs(int x)
{
	dep[x]=dep[fa[x]]+1;
	for(int i=head[x];i;i=nxt[i])
	{
		int to=ver[i];
		if(to==fa[x]) continue;
		if(!dep[to])
		{
			fa[to]=x,dfs(to),odd[x]+=odd[to];
			even[x]=min(even[x],even[to]),minn[x]=min(minn[x],minn[to]);
		}
		else if((dep[x]-dep[to])&1)
		{
			if(dep[x]>dep[to])
				even[x]=min(even[x],dep[to]);
		}
		else if(dep[to]<dep[x])
			odd[x]++,odd[fa[to]]--,all++,minn[x]=min(minn[x],dep[to]);
	}
}
void solve()
{
	n=read(); m=read(); bit.reset(); flag=false;
	for(int i=1;i<=m;i++) s[i].a=read(),s[i].b=read(),s[i].c=read();
	bit[s[1].a]=bit[s[1].b]=bit[s[1].c]=true;
	for(int i=2;i<=m;i++)
	{
		bitset<N> b; b.reset(); b[s[i].a]=b[s[i].b]=b[s[i].c]=true;
		if(!(bit&b).count()) return printf("no\n"),void(); bit&=b;
	}
	for(int i=1;i<=n;i++) if(bit[i]){pos=i;break;}
	for(int i=1;i<=n&&!flag;i++)
	{
		tot=1; all=0;
		for(int j=1;j<=n;j++) head[j]=odd[j]=dep[j]=fa[j]=0,even[j]=minn[j]=INF;
		for(int j=1;j<=m;j++)
		{
			int a=s[j].a,b=s[j].b,c=s[j].c;
			if(a==pos&&b!=i&&c!=i) add_edge(b,c),add_edge(c,b);
			else if(b==pos&&a!=i&&c!=i) add_edge(a,c),add_edge(c,a);
			else if(c==pos&&a!=i&&b!=i) add_edge(a,b),add_edge(b,a);
		}
		for(int j=1;j<=n;j++) if(j!=i&&j!=pos&&!dep[j]) dfs(j);
		for(int j=1;j<=n&&!flag;j++)
			if(odd[j]==all)
			{
				jud=true;
				for(int k=head[j];k&&jud;k=nxt[k])
				{
					int to=ver[k];
					if(dep[to]>dep[j]&&even[to]<dep[j]&&minn[to]<dep[j]) jud=false;
				}
				flag|=jud;
			}
	}
	if(flag) printf("yes\n"); else printf("no\n");
}
signed main()
{
	freopen("river.in","r",stdin); freopen("river.out","w",stdout);
	T=read(); while(T--) solve(); return 0;
}

标签:ch,NOIP,int,long,dep,64,ull,模拟,define
来源: https://www.cnblogs.com/Varuxn/p/15359965.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有