加载中…

返回上一页

2022NOIP A层联测18

游记暂咕,以后心情好再写

下发文件(密码为原 accoders 比赛密码)

算术

把每一种情况列出来不难发现合法组合为小于等于 1 的数和大于 0 的数,乘一下,记得去 11 的重.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 1000001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
ll n,a[maxn];
ll zheng,less1,is1;
int main()
{
	freopen("a.in","r",stdin); freopen("a.out","w",stdout);
	n=read(); for(rll i=1;i<=n;i++) a[i]=read();
	for(rll i=1;i<=n;i++) { if(a[i]>0) zheng++; if(a[i]<=1) less1++; if(a[i]==1) is1++; }
	write(zheng*less1-(is1*(is1+1)>>1));
	return 0;
}

刷墙

简单的区间 dp,但是确实需要一定的思维量.

首先看到最多只有 600 个点,但是区间大小是 1e9,就需要先离散化一下.

dp[l][r] 为从第 l 端点到第 r 端点之间最多有多少种颜色. 枚举点 mid,把 [mid , mid + 1] 的颜色先放上,再用两边 [l , mid][mid + 1 , r] 的已计算值更新中间的值.

点击查看代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define maxn 601
#define pll pair<ll,ll>
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
ll n,len,ans;
ll l[maxn],r[maxn],a[maxn],dp[maxn][maxn],s[maxn][maxn];
int main()
{
	freopen("b.in","r",stdin); freopen("b.out","w",stdout);
	n=read(); for(rll i=1;i<=n;i++) a[(i<<1)-1]=l[i]=read(),a[i<<1]=r[i]=read();
	sort(a+1,a+(n<<1)+1);len=unique(a+1,a+(n<<1)+1)-a-1;
	for(rll i=1;i<=n;i++) s[lower_bound(a+1,a+len+1,l[i])-a][lower_bound(a+1,a+len+1,r[i])-a]++;
	for(rll i=1;i<=len;i++) for(rll j=1;j<=len;j++) s[i][j]+=s[i-1][j]; for(rll i=1;i<=len;i++) for(rll j=1;j<=len;j++) s[i][j]+=s[i][j-1];
	for(rll i=1;i<=len;i++) for(rll l=1,r=i;l<=len-i+1;l++,r++) for(rll mid=l;mid<r;mid++)
		dp[l][r]=max(dp[l][r],dp[l][mid]+dp[mid+1][r]+(bool)(s[mid][r]-s[l-1][r]-s[mid][mid]+s[l-1][mid]));
	write(dp[1][len]);
	return 0;
}

重复

先对字符串哈希一下,然后用 n2 的时间找到子串 a 和子串 b 相同的所有前缀并累加一个前缀和.

然后用类似的方法找到子串 bc 和子串 ef 的相同1前缀,这里用了个二分能更快找到,其实硬暴力应该也没问题. 最后累加答案.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 5001
#define ull unsigned ll
#define bs 131
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
ll n,ans,lcp[maxn][maxn],sum[maxn][maxn];
ull Hash[maxn],pw[maxn];
char s[maxn];
inline ull ksm(rg ull a,rll b) { rg ull ans=1; for(rll i=b;i;i>>=1) { if(i&1) ans*=a; a*=a; } return ans; }
inline ull gethash(rll x,rll y) { return Hash[y]-Hash[x-1]*pw[y-x+1]; }
inline bool chk(rll i,rll j,rll x) { return gethash(i,i+x-1)==gethash(j,j+x-1); }
int main()
{
	freopen("c.in","r",stdin); freopen("c.out","w",stdout);
	scanf("%s",s+1);n=strlen(s+1); pw[0]=1; for(rll i=1;i<=n;i++) pw[i]=pw[i-1]*bs;
	for(rll i=1;i<=n;i++) Hash[i]=Hash[i-1]*bs+s[i];
	for(rll i=2;i<=n;i++)// string a,b
	{
		for(rll j=i-1;j&&(i<<1)-j-1<=n;j--) lcp[i][j]=gethash(j,i-1)==gethash(i,(i<<1)-j-1);
		for(rll j=i-1;j;j--) sum[i][j]=sum[i][j+1]+(lcp[i][j]+=lcp[i][j+1]);// ,cout<<i<<' '<<j<<' '<<lcp[i][j]<<endl;
	}
	for(rll i=2;i<=n;i++) for(rll j=i+3;j<n;j++) if(s[i]==s[j]&&s[i+1]==s[j+1])// string bc,ef
	{
		rll l=3,r=n-j+1,len=2;
		while(l<=r) { rll mid=(l+r)>>1; if(chk(i,j,mid)) len=mid,l=mid+1; else r=mid-1; }
		len=min(len,j-i-1); if(len<=i) ans+=sum[i][i-len+1]; else ans+=sum[i][1]+(len-i)*lcp[i][1];
	}
	write(ans);
	return 0;
}

公交

数据结构维护长链剖分,没改……

posted @ 2022-10-31 19:21  1Liu  阅读(27)  评论(0编辑  收藏  举报