CSP-S模拟5
???博客园自动保存呢?
我刚打完就没了?????
下次一定本地写
因为某些原因,原来写完的题解突然没了,于是有了现在这个
下次一定在本地写
A. F
枚举 和哪个数异或然后暴力检查即可
不会有人跟我一样傻打 吧
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2005;
inline int read(){
int x = 0; char c = getchar();
while(c < '0' || c > '9')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c <= '9' && c >= '0');
return x;
}
int n, a[maxn], b[maxn], idb[maxn];
struct tire{
int ch[1000005][2], size[1000005], root = 1, cnt = 1;
int insert(int x){
int now = root;
for(int i = 30; i >= 0; --i){
int s = (x >> i) & 1;
if(!ch[now][s])ch[now][s] = ++cnt;
now = ch[now][s];
}
++size[now];
return now;
}
int sta[maxn];
bool check(int x){
int top = 0, flag = 1;
for(int i = 2; i <= n; ++i){
int now = root;
for(int j = 30; j >= 0; --j){
if(!now){flag = 0; break;}
if((x >> j) & 1)now = ch[now][1 xor ((a[i] >> j) & 1)];
else now = ch[now][(a[i] >> j) & 1];
}
if(!now || size[now] == 0){flag = 0; break;}
--size[now]; sta[++top] = now;
if(!flag)break;
}
for(int i = top; i > 0; --i)++size[sta[i]];
return flag;
}
}t;
set<int>ans;
int main(){
freopen("f.in","r",stdin);
freopen("f.out","w",stdout);
n = read();
for(int i = 1; i <= n; ++i)a[i] = read();
for(int i = 1; i <= n; ++i)b[i] = read();
for(int i = 1; i <= n; ++i)idb[i] = t.insert(b[i]);
for(int i = 1; i <= n; ++i){
int x = (a[1] xor b[i]);
if(ans.count(x))continue;
--t.size[idb[i]];
if(t.check(x))ans.insert(x);
++t.size[idb[i]];
}
printf("%d\n",(int)ans.size());
for(int x : ans)printf("%d\n",x);
return 0;
}
B. S
表示填了前 个位置, 用了 个 , 个 最后一个填的是
转移枚举下一个填啥
发现同一种颜色之间的相对位置不会改变,所以可以方便知道下一个填的颜色原来的位置
发现新位置为原位置 + 移到他前面的颜色的个数
预处理每个位置前面有多少某种颜色,然后就可以方便转移了
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 4005;
const int inf = 0x3f3f3f3f;
int n; char c[maxn];
int cr, cg, cy;
int cnt[maxn][3], posr[maxn], posg[maxn], posy[maxn];
int f[2][maxn][maxn][3];
int main(){
// freopen("s.in","r",stdin);
// freopen("s.out","w",stdout);
scanf("%d%s",&n,c + 1);
for(int i = 1; i <= n; ++i){
if(c[i] == 'R')posr[++cr] = i;
else if(c[i] == 'G')posg[++cg] = i;
else if(c[i] == 'Y')posy[++cy] = i;
cnt[i][0] = cr; cnt[i][1] = cg; cnt[i][2] = cy;
}
if(max(max(cr, cg), cy) > (n + 1) / 2){
printf("-1\n");return 0;
}
memset(f, 0x3f, sizeof(f));
f[1][1][0][0] = posr[1] - 1;
f[1][0][1][1] = posg[1] - 1;
f[1][0][0][2] = posy[1] - 1;
for(int i = 1; i < n; ++i){
int zt = i & 1, nzt = 1 - zt;
for(int x = 0; x <= cr; ++x){
if(x > i)break;
for(int y = 0; y <= cg; ++y){
if(x + y > i)break;
int z = i - x - y;
if(z > cy)continue;
int pr = posr[x + 1], pg = posg[y + 1], py = posy[z + 1];
int dr = pr - i - 1 + max(0, y - cnt[pr][1]) + max(0, z - cnt[pr][2]);
int dg = pg - i - 1 + max(0, x - cnt[pg][0]) + max(0, z - cnt[pg][2]);
int dy = py - i - 1 + max(0, x - cnt[py][0]) + max(0, y - cnt[py][1]);
if(x < cr)f[nzt][x + 1][y][0] = min(f[nzt][x + 1][y][0], min(f[zt][x][y][1], f[zt][x][y][2]) + dr);
if(y < cg)f[nzt][x][y + 1][1] = min(f[nzt][x][y + 1][1], min(f[zt][x][y][0], f[zt][x][y][2]) + dg);
if(z < cy)f[nzt][x][y][2] = min(f[nzt][x][y][2], min(f[zt][x][y][0], f[zt][x][y][1]) + dy);
}
}
for(int a = 0; a <= cr; ++a)for(int b = 0; b <= cg; ++b)f[zt][a][b][0] = f[zt][a][b][1] = f[zt][a][b][2] = inf;
}
printf("%d\n",min(min(f[n & 1][cr][cg][0], f[n & 1][cr][cg][1]), f[n & 1][cr][cg][2]));
return 0;
}
C. Y
每个人都传给下一个人至少一个球,那么可以等价所有人拿回若干个,至少有一个人不给下一个人传球
枚举第一个这样的人,断环,
设 表示第 个人传给下一个人 个球
然后发现我们只需要维护
然后转移可以写成矩阵,,每次取的是一个前缀和一个后缀,预处理出来即可
我还不知道
左右相加移项即可
从数奥大佬 ( 说是姐姐?)那里搞来的方法
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1000005;
const int mod = 1e9 + 7;
const int inv2 = 500000004;
const int inv6 = 166666668;
inline int read(){
int x = 0; char c = getchar();
while(c < '0' || c > '9')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c <= '9' && c >= '0');
return x;
}
int a[maxn], n, ans;
int dc(int l, int r, int x){
if(r < l)return 0;
return 1ll * (r + l) * x % mod * inv2 % mod;
}
int sf(int x){
return 1ll * x * (x + 1) % mod * (x + x + 1) % mod * inv6 % mod;
}
struct matrix{
int a[2][2];
matrix(){a[0][0] = a[0][1] = a[1][0] = a[1][1] = 0;}
void unlimit(int x){
int s1 = dc(1, x, x), s2 = sf(x);
a[0][0] = s1; a[0][1] = (1ll * s1 * x % mod - s2 + mod) % mod;
a[1][0] = x + 1; a[1][1] = s1;
}
void limit(int x){
int s1 = dc(1, x, x), s2 = sf(x);
a[0][0] = dc(1, x - 1, x - 1); a[0][1] = (1ll * s1 * x % mod - s2 + mod) % mod;
a[1][0] = x; a[1][1] = s1;
}
friend matrix operator * (const matrix &x, const matrix &y){
matrix c;
for(int i = 0; i <= 1; ++i)
for(int k = 0; k <= 1; ++k)
for(int j = 0; j <= 1; ++j)
c.a[i][j] = (c.a[i][j] + 1ll * x.a[i][k] * y.a[k][j] % mod) % mod;
return c;
}
}m[maxn + maxn];
int main(){
freopen("y.in","r",stdin);
freopen("y.out","w",stdout);
n = read();
for(int i = 1; i <= n; ++i)a[i] = read();
for(int i = 1; i <= n; ++i)m[i].unlimit(a[i]);
for(int i = 1; i <= n; ++i)m[i + n].limit(a[i]);
for(int i = n + 2; i <= n + n; ++i)m[i] = m[i - 1] * m[i];
for(int i = n - 1; i > 0; --i)m[i] = m[i] * m[i + 1];
int ans = 0;
for(int l = 1; l <= n; ++l){
matrix now; now.a[0][0] = 1;
if(l != n)now = now * m[l + 1];
if(l != 1)now = now * m[l + n - 1];
ans = (ans + 1ll * now.a[0][0] * a[l] % mod + now.a[0][1]) % mod;
}
ans = (ans % mod + mod) % mod;
printf("%d\n",ans);
return 0;
}
写成正三角型,转 得到两个三角和原来的对应相加每个位置都变成了 一共 个数
可惜放不了图片(姐姐?的字写的挺好看)
D. O
upd : 写了。题解,感谢 大佬的耐心讲解,我的做法跟他在处理某些细节上略有不同(
比他少棵线段树)
咕了
和 拼凑了一个 水了一发
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】