ICode9

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

模拟64 考试总结

2021-10-04 07:00:06  阅读:171  来源: 互联网

标签:nxt return int long 64 模拟 freopen inline 考试


咕 咕 咕

考试经过

题目基本不会,于是猛冲暴力
T1看见同余不会,狂写部分分;T2看见字符串不会,哈希乱搞;T3看见矩阵不会,暴力走人;T4啥玩意看不懂,果断弃掉
60+70+30+0=160,算是冲满了,rk6

T1.三元组

其实压根不是个数论题。。。
你发现根本想不出任何数论技巧,所以考虑放弃而把它做成数据结构题
暴力枚举\(n^3\),发现左边的一次项是连续的,想怎么用这个性质
枚举中间的\(b\),由于左边连续,所以会形成若干个\(0-k-1\)的区间,每有这样一个区间,右边所有的\(i^3\)一定能在左边找到对应的值,因为它覆盖了整个区间,直接累加答案就好。剩下不满的区间可以利用在值域上开树状数组维护,也算比较套路了
还是先插满,每次左移,维护,删除,记得取模边界注意一下

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=100050;
int n,k;
struct bit{
   int b[N];
   inline void cl(){memset(b,0,sizeof(b));}
   inline int lowbit(int x){return x&(-x);}
   inline void add(int x,int v){for(int i=x;i<=k;i+=lowbit(i))b[i]+=v;}
   inline int getsum(int p){int s=0;for(int i=p;i;i-=lowbit(i))s+=b[i];return s;}
   inline int get(int l,int r)
   {
   	if(l>r)return 0;
   	if(!l)return getsum(r);
   	return getsum(r)-getsum(l-1);
   }
}tr;
inline int gan(int x)
{
   int ga=x%k;
   if(ga)return ga;
   else return k;
}
signed main()
{
   freopen("exclaim.in","r",stdin);
   freopen("exclaim.out","w",stdout);
   int t;cin>>t;
   for(int T=1;T<=t;T++)
   {
   	scanf("%lld%lld",&n,&k);tr.cl();
   	for(int i=1;i<=n;i++)tr.add(gan(i*i*i),1);
   	int ans=0;
   	for(int i=1;i<=n;i++)
   	{	
   		int s=i/k,p=gan(i),ga=gan(i*i);
   		ans+=(s*(n-i+1));
   		if(p==k){tr.add(gan(i*i*i),-1);continue;}
   		int l=gan(ga+1),r=gan(ga+p);
   		if(l<=r)ans+=tr.get(l,r);
   		else ans+=tr.get(1,r)+tr.get(l,k); 
   		tr.add(gan(i*i*i),-1);
   	}
   	printf("Case %lld: %lld\n",T,ans);
   }
   return 0;
}	

T2.简单的字符串

简单是因为可以哈希水过去,优化一下基本卡不掉
正解是用了结论,首先合法串一定可以变成形如\(uvvu\)的形式,循环同构性质
设前面的串是\(A\),后面为\(B\),结论是\(u,v\)必有一个是\(AB\)或\(BA\)的最长\(border\)
证明建议右转,%%%
如果是\(u\)的话可以利用 \(border\)理论,跳两次找到大于一半\(border\)的公差,再直接跳到小于等于一半的位置,复杂度是正确的
否则的话枚举中间点,向两边扩展,中间保持最长匹配,一直哈希就好了
总复杂度\(n^2\),纯正解

#include <bits/stdc++.h>
using namespace std;
#define ull unsigned long long
const int N=5050;
ull h[N],ps[N];bool an[N][N];
int a[N],n,nxt[N][N];
ull get(int l,int r){if(l>r)return 0;return h[r]-h[l-1]*ps[r-l+1];}
signed main()
{
	freopen("s.in","r",stdin);
	freopen("s.out","w",stdout);
	cin>>n;int ans=0;
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	ps[0]=1;for(int i=1;i<=n;i++)ps[i]=ps[i-1]*13331;
	for(int i=1;i<=n;i++)h[i]=h[i-1]*13331+a[i];
	for(int i=1;i<=n;i++)
	{
		int p=i-1;nxt[i][i]=p;
		for(int j=i+1;j<=n;j++)
		{
			while(p>i-1&&a[j]!=a[p+1])p=nxt[i][p];
			if(a[j]==a[p+1])p++;
			nxt[i][j]=p;
		}
	}
	for(int i=1;i<n;i++)
	{
		int lmid=i,rmid=i+1,ll=lmid,rr=rmid;
		int lp=rmid,rp=lmid;
		while(ll>=1&&rr<=n)
		{
			if(get(ll,lmid)==get(rmid,rr))
			{
				lp=ll,rp=rr;
				an[ll][rr]=1;	
			}
			else
			{
				if(get(ll,lp-1)==get(rp+1,rr))
				an[ll][rr]=1;
			}
			ll--,rr++;
		}
	}
	for(int i=1;i<n;i++)
	{
		for(int j=i+1;j<=n;j+=2)
		{
			if(an[i][j])continue;
			int lmid=(i+j)>>1,rmid=lmid+1;
			int nx1=nxt[i][j],nx2=nxt[i][nx1],ma;
			if(nx1<i)continue;
			if(nx1<=lmid)ma=nx1;
			else if(nx2<i)continue;
			else if(nx2<=lmid)ma=nx2;
			else 
			{
				int s=nx1-nx2,pp=nx1-((nx1-rmid+1)/s)*s;
				if(pp<=lmid)ma=pp;else ma=nxt[i][pp];
			}
			if(ma==lmid||get(ma+1,lmid)==get(rmid,j-(ma-i+1)))an[i][j]=1;
		}
	}
	for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j+=2)
	  if(an[i][j])ans++;
	cout<<ans<<endl;
	return 0;
}

T3.环路

考场时就想到了要做矩阵乘,每次算一遍对角线上答案之和再累加
现在优化显然应该快速幂,想能不能把答案存在某个地方
image
就这么配,扩大一倍,这样就把答案保存在了右上方1的位置,可以思考矩阵乘的实现过程
实现时可能稍微卡常

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=205;
char c[N][N];
int a[N][N],pp[N][N],p[N][N],n,m,k;
inline void mul()
{
	memset(pp,0,sizeof(pp));
	for(int i=1;i<=2*n;i++)
	 for(int k=1;k<=2*n;k++)
	 {
	  	if(!a[i][k])continue;
	  	for(int j=1;j<=2*n;j++)
	  	 pp[i][j]=(pp[i][j]+a[i][k]*p[k][j]%m)%m;
	 }
	memcpy(a,pp,sizeof(pp));
}
inline void gan()
{
	memset(pp,0,sizeof(pp));
	for(int i=1;i<=2*n;i++)
	 for(int k=1;k<=2*n;k++)
	 {
	 	if(!p[i][k])continue;
	 	for(int j=1;j<=2*n;j++)
	 	 pp[i][j]=(pp[i][j]+p[i][k]*p[k][j]%m)%m;
	 }
	memcpy(p,pp,sizeof(pp));
}
inline void ksm(int x)
{
	for(;x;x>>=1)
	{
		if(x&1)mul();
		gan();		
	}
}
signed main()
{	
	freopen("tour.in","r",stdin);
	freopen("tour.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++)scanf("%s",c[i]+1);
	cin>>k>>m;
	for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
     if(c[i][j]=='Y')p[i][j]=1;
   memcpy(a,p,sizeof(p)); 
   for(int i=1;i<=n;i++)p[i][i+n]=p[i+n][i+n]=1;
   ksm(k-2);int ans=0;
   for(int i=1;i<=n;i++)ans=(ans+a[i][i]+a[i][i+n])%m;
	cout<<ans<<endl;
   return 0;
}

T4.过河

没改出来,咕

考试总结

时间还是分配好,总体在预期之内
暴力和正解有时差不了多少,关键是思维能不能上去
要把状态保持住

标签:nxt,return,int,long,64,模拟,freopen,inline,考试
来源: https://www.cnblogs.com/PMZG/p/15365662.html

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

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

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

ICode9版权所有