四川大学2021SCUACM新生赛决赛大部分题解(差分dp线段树……)
Posted hans774882968
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了四川大学2021SCUACM新生赛决赛大部分题解(差分dp线段树……)相关的知识,希望对你有一定的参考价值。
这套题至少要过8题才能算是有脑这种器官,过9题才是正常人。很可惜我没有脑~
B
这题我比赛后学会的,还没补代码。
首先考虑对查询按x
升序排序。我们的主要思想是填平之前求出的结果与当前问题的差距。这里”差距“指的是一个数据结构,它就是一个数组b[]
,处理到当前查询的时候,b[i]
表示max(a[i~前一个询问的x])
。
如何填平差距?设第一个a
值大于i
的点为L[i]
,设当前查询的参数为curL,curR,curX
。则[L[i]+1~i]
的max(a[i~curX])
都是a[i]
,而[1~L[i]]
的max(a[i~curX])
都不是a[i]
。因此[1~L[i]]
的b
数组信息可复用,对b[L[i]+1~i]
进行区间覆盖即可。当前查询的答案就是sum(b[curL,curR])
。
L
数组就是个简单的单调栈模板。而b
数组的维护,使用线段树即可。
D
拆位+差分。首先各个位互不影响,拆位是显然的。拆位后发现区间or值为1的那些信息没有用。所以差分求出必选为0的所有点即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)
const int N = 1e6 + 5;
const int mod = 1e9 + 7;
int dx[4] = -1,1,0,0,dy[4] = 0,0,-1,1;
int n,m,L[N],R[N],x[N],d[N];
void dbg()puts("");
template<typename T, typename... R>void dbg(const T &f, const R &... r)
cout << f << " ";
dbg(r...);
template<typename Type>inline void read(Type &xx)
Type f = 1;char ch;xx = 0;
for(ch = getchar();ch < '0' || ch > '9';ch = getchar()) if(ch == '-') f = -1;
for(;ch >= '0' && ch <= '9';ch = getchar()) xx = xx * 10 + ch - '0';
xx *= f;
int main(int argc, char** argv)
while(~scanf("%d%d",&n,&m))
rep(i,1,m)
read(L[i]);read(R[i]);read(x[i]);
LL ans = 0;
re_(i,0,30)
rep(j,1,n+1) d[j] = 0;
rep(j,1,m)
if(x[j]>>i&1) continue;
d[L[j]]++;d[R[j]+1]--;
rep(j,1,n) d[j] += d[j-1];
int u = 0;
rep(j,1,n) u += (d[j] == 0);
ans += u*(1LL<<i);
printf("%lld\\n",ans);
return 0;
E
题目名叫”羊工八刀“似乎是提醒我们用差分。但我是dp做的。设当前点为x
,则当前点的贡献:
sum((x-x[j])^2) = t*x*x + sum(x[j]^2) - 2*x*sum(x[j])
。因此维护3个dp数组即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)
const int N = 1e6 + 5;
const int mod = 1e9 + 7;
int dx[4] = -1,1,0,0,dy[4] = 0,0,-1,1;
int n;LL c[N],s1[N],s2[N],dp[N];char s[N];
void dbg()puts("");
template<typename T, typename... R>void dbg(const T &f, const R &... r)
cout << f << " ";
dbg(r...);
template<typename Type>inline void read(Type &xx)
Type f = 1;char ch;xx = 0;
for(ch = getchar();ch < '0' || ch > '9';ch = getchar()) if(ch == '-') f = -1;
for(;ch >= '0' && ch <= '9';ch = getchar()) xx = xx * 10 + ch - '0';
xx *= f;
int main(int argc, char** argv)
int T;read(T);
while(T--)
read(n);
scanf("%s",s+1);
rep(i,1,n) c[i] = s1[i] = s2[i] = dp[i] = 0;
rep(i,1,n)
c[i] = c[i-1] + (s[i] == '1');
s1[i] = s1[i-1] + (s[i] == '1' ? i : 0);
s2[i] = s2[i-1] + (s[i] == '1' ? 1LL*i*i%mod : 0);
if(s[i] != '1') continue;
dp[i] = ((c[i]*i%mod*i%mod+s2[i]-2*i*s1[i]%mod)%mod+mod)%mod;
printf("%d\\n",accumulate(dp+1,dp+n+1,0,[](int tot,int v)return (tot+v)%mod;));
return 0;
F
小模拟。题干容易引起歧义,尤其是对于真的玩过植物大战僵尸的。比赛时猜出的题目要求是:不能有植物可被偷走。所以做法就是看每一个植物是否有可能被偷走,很水……
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)
const int N = 8,M = 11;
const int INF = 1e9;
int dx[9] = -1,-1,0,1,1,1,0,-1,0,dy[9] = 0,1,1,1,0,-1,-1,-1,0;
int n;
char a[N][M];bool prot[N][M];int val[N][M];
void dbg()puts("");
template<typename T, typename... R>void dbg(const T &f, const R &... r)
cout << f << " ";
dbg(r...);
template<typename Type>inline void read(Type &xx)
Type f = 1;char ch;xx = 0;
for(ch = getchar();ch < '0' || ch > '9';ch = getchar()) if(ch == '-') f = -1;
for(;ch >= '0' && ch <= '9';ch = getchar()) xx = xx * 10 + ch - '0';
xx *= f;
bool out(int x,int y)
return x < 0 || x >= 6 || y < 0 || y >= 9;
bool solve()
memset(prot,0,sizeof prot);
memset(val,0,sizeof val);
re_(i,0,6) re_(j,0,9) if(a[i][j] == '3')
re_(t,0,9)
int x = i+dx[t],y = j+dy[t];
if(out(x,y)) continue;
prot[x][y] = true;
re_(i,0,6) re_(j,0,9) if(a[i][j] == '4' || a[i][j] == '0') prot[i][j] = true;
re_(i,0,6) re_(j,0,9)
if(a[i][j] == '1')
rep(k,j+1,min(8,j+4)) val[i][k]++;
if(a[i][j] == '2')
re_(t,0,9)
int x = i+dx[t],y = j+dy[t];
if(out(x,y)) continue;
val[x][y]++;
// re_(i,0,6) re_(j,0,9) cout<<(prot[i][j]?'x':a[i][j])<< " \\n"[j==8];//
// re_(i,0,6) re_(j,0,9) cout<<(prot[i][j]?-1:val[i][j])<< " \\n"[j==8];//
re_(i,0,6) re_(j,0,9)
if(prot[i][j]) continue;
if(val[i][j] < 2) return false;
return true;
int main(int argc, char** argv)
int T;read(T);
while(T--)
re_(i,0,6) scanf("%s",a[i]);
puts(solve() ? "Yes" : "No");
return 0;
G
这题和校内题不同。校内题是问int范围的最大质数,签到。这题是问[2,x]范围的最大质数。int范围内素数间距应该不太大,大概直接暴力是没问题的。我用的素性测试。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_2016广东工业大学新生杯决赛网络同步赛暨全国新生邀请赛 题解&源码
2021年第十二届蓝桥杯大赛软件赛决赛C/C++大学A组 个人部分题解