CSP模拟赛题解
CSP模拟16#
T1 : 糖果#
这道题的思路很巧妙,明白了思路之后可以轻松切掉。既然这是求异或和,那根据异或的性质,如果是分为奇数段,那最后就会消为3段;如果是偶数段,最后会消为2段。特别要注意的是如果最后是两段的话,总的异或和一定为0。对于奇数段,先找到一个前缀的异或和,让它等于总的异或值,然后找到存不存在一个后缀异或和等于前缀(也就是总的异或和),然后这道题就可以轻松的切掉了……
代码实现:
点击查看代码
int n, temp1, temp2, T;
int a[100010], sum1[100010], sum2[100010];
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> T;
while (T--) {
memset(sum1, 0, sizeof(sum1));
memset(sum2, 0, sizeof(sum2));
temp1 = 100010; temp2 = 0;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
sum1[i] = sum1[i-1] ^ a[i];
}
for (int i = n; i >= 1; i--)
sum2[i] = sum2[i+1] ^ a[i];
if (!sum1[n]) cout << "YES" << '\n';
else {
for (int i = 1; i <= n; i++)
if (sum1[i] == sum1[n]) {
temp1 = i;
break;
}
for (int i = n; i >= 1; i--)
if (sum2[i] == sum1[n]) {
temp2 = i;
break;
}
if (temp1 < temp2) cout << "YES" << '\n';
else cout << "NO" << '\n';
}
}
return 0;
}
CSP模拟17#
T1:弹珠游戏#
这道题要求最大值和最小值的和最小的情况,于是我们考虑贪心,也就是我们尽量让能拿全的人先全部拿全,这样才可以让当前发的弹珠发挥最大的作用,因此我们在考虑当前弹珠发挥的作用时,不需要考虑已经含有这种弹珠的人。
举个例子:
当前要发的弹珠是
代码实现:
点击查看代码
#define int long long
#define R 1
#define G 2
#define B 3
#define RB 4
#define RG 5
#define BG 6
using namespace std;
const int mod = 998244353;
int n, ans = 1;
int cnt[10];
char op;
signed main() {
// freopen("../cin/a.txt","r",stdin);
cin >> n; cnt[0] = n;
for (int i = 1; i <= n*3; i++) {
cin >> op;7
if (op == 'R') {
if (cnt[BG]) {
ans = ans * cnt[BG] % mod;
cnt[BG]--;
} else if (cnt[G]) {
ans = ans * cnt[G] % mod;
cnt[G]--;
cnt[RG]++;4/..0516602
} else if (cnt[B]) {
ans = ans * cnt[B] % mod;
cnt[B]--;
cnt[RB]++;
} else {
ans = ans * cnt[0] % mod;
cnt[R]++;
cnt[0]--;
}
}
if (op == 'B') {
if (cnt[RG]) {
ans = ans * cnt[RG] % mod;
cnt[RG]--;
} else if (cnt[R]) {
ans = ans * cnt [R] % mod;
cnt[R]--;
cnt[RB]++;
} else if (cnt[G]) {
ans = ans * cnt[G] % mod;
cnt[G]--;
cnt[BG]++;
} else{
ans = ans * cnt[0] % mod;
cnt[0]--;
cnt[B]++;
}
}
if (op == 'G') {
if (cnt[RB]) {
ans = ans * cnt[RB] % mod;
cnt[RB]--;
} else if (cnt[R]) {
ans = ans * cnt[R] % mod;
cnt[R]--; cnt[RG]++;
} else if (cnt[B]) {
ans = ans * cnt[B] % mod;
cnt[B]--; cnt[BG]++;
} else {
ans = ans * cnt[0] % mod;
cnt[0]--; cnt[G]++;
}
}
}
cout << ans << '\n';
return 0;
}
T2:晚会#
题目说的是让你去判断能否满足不存在“不友好”的关系,如果能满足,则输出所有人的之间的
答案是用类似于
代码实现:
点击查看代码
struct node {
int from, to, val;
friend bool operator <(node x1, node x2) {
return x1.val > x2.val;
}
} edge[M];
int n, m, ans, cnt;
int fa[M], vis[M], minn[M], size[M], bel[M];
int Find(int x) {
if (x == fa[x]) return x;
return fa[x] = Find(fa[x]);
}
signed main() {
n = read(), m = read();
for (int i = 1; i <= n; i++)
fa[i] = i, size[i] = 1, minn[i] = 0x7f7f7f7f;
for (int i = 1; i <= m; i++)
edge[i].from = read(), edge[i].to = read(), edge[i].val = read();
sort(edge + 1, edge + 1 + m);
for (int i = 1; i <= m; i++) {
int fx = Find(edge[i].from), fy = Find(edge[i].to), z=edge[i].val;
if (fx != fy) {
fa[fy] = fx;
ans += size[fx] * size[fy] * z;
minn[fx] = min(min(minn[fx], z), minn[fy]);
size[fx] += size[fy];
} else {
if (z < minn[fx]) {
write(-1); putchar('\n');
return 0;
}
minn[fx] = min(minn[fx], z);
}
}
for (int i = 1; i <= n; i++) {
int fx = Find(i);
if (vis[fx]) continue;
bel[++cnt] = fx;
vis[fx] = 1;
for (int j = 1; j <= cnt - 1; j++)
ans += size[bel[cnt]] * size[bel[j]];
}
write(ans); putchar('\n');
return 0;
}
CSP模拟18#
T1:The Third Letter#
这是带权并查集的模板题,但是我不会。你可以让在前面的是在后面的祖先,也可以反过来,这都无所谓,主要是并查集的权值传递,我们用一个
代码实现:
点击查看代码
int n, m, x, y, z, p, T;
int d[300010], f[300010];
int Find(int x) {
if (x == f[x])
return x;
else {
int fx = Find(f[x]);
d[x] += d[f[x]];
f[x] = fx;
return f[x];
}
}
signed main() {
cin >> T;
while (T--) {
p = 0;
cin >> n >> m;
for (int i = 1; i <= n; i++)
d[i] = 0, f[i] = i;
for (int i = 1; i <= m; i++) {
cin >> x >> y >> z;
if (p == 1)
continue;
int fx = Find(x), fy = Find(y);
if (fx != fy) {
f[fy] = fx;
d[fy] = d[x] + z - d[y];
} else {
if (d[y] - d[x] != z) {
p = 1;
}
}
}
if (!p)
cout << "YES" << '\n';
else
cout << "NO" << '\n';
}
return 0;
}
T2:Ina of the Mountain#
先咕了,放个代码先。
代码实现:
点击查看代码
priority_queue <int> q;
const int maxn = 1e9+10;
int n, k, ans, sum, T;
int a[200010];
signed main() {
cin >> T;
while (T--) {
while (!q.empty()) q.pop();
cin >> n >> k;
for (int i = 1; i <= n; i++)
cin >> a[i];
sum = 0; ans = 0;
for (int i = 1; i <= n; i++) {
int A, B = (a[i] - a[i-1] + k) % k;
if (!B) continue;
A = B - k;
if (sum + A >= 0) {
sum += A;
q.push(-B);
} else {
int mn;
if (!q.empty()) mn = -q.top();
else mn = maxn;
if (mn < B) {
sum += k + A; ans += mn;
q.pop(); q.push(-B);
} else {
sum += B; ans += B;
}
}
}
cout << ans << '\n';
}
return 0;
}
CSP模拟19#
T1:Strange Function#
先观察数据范围,显然
T2:DZY Loves Modification#
这道题就是利用了贪心的思想,可以使用优先队列存每一行和每一列的和,先分别对行和列进行处理,考虑到最后的答案是和选行或列的顺序无关的,行与行或列与列之间前后选择,互相没有影响,最后只需要减去选行选列的交点的个数乘
代码实现:
点击查看代码
const int maxn = 1e18;
priority_queue<int>line, row;
int n, m, k, p, res, cntl, cntr, ans = -maxn;
int a[1010][1010], suml[1000010], sumr[1000100];
signed main() {
cin >> n >> m >> k >> p;
for (int i = 1; i <= n; i++) {
res = 0;
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
res += a[i][j];
}
line.push(res);
}
for (int j = 1; j <= m; j++) {
res = 0;
for (int i = 1; i <= n; i++) {
res += a[i][j];
}
row.push(res);
}
for (int i = 1; i <= k; i++) {
int x = line.top();
line.pop();
suml[i] = suml[i - 1] + x;
x -= m * p;
line.push(x);
}
for (int j = 1; j <= k; j++) {
int y = row.top();
row.pop();
sumr[j] = sumr[j - 1] + y;
y -= n * p;
row.push(y);
}
for (int z = 0; z <= k; z++) {
ans = max(ans, suml[z] + sumr[k - z] - p * (k - z) * z);
}
cout << ans << '\n';
return 0;
}
CSP模拟21#
T1:[CEOI2016] kangaroo#
思路我想不到,就是将一个数看成一个块,相当于将
插入新块:
合并块:
起(终)点的合并相当于在块中加一个元素:
具体看代码即可,我觉得应该可以明白吧。
代码实现:
点击查看代码
#define int long long
using namespace std;
const int mod=1e9+7;
int n,s,t;
int f[2010][2010];
signed main()
{
cin >> n >> s >> t;
f[1][1]=1;
for (int i=2;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
if (i==s || i==t)
{
f[i][j]+=f[i-1][j]+f[i-1][j-1];
f[i][j]%=mod;
continue;
}
int res=(i>s)+(i>t);
f[i][j]+=f[i-1][j-1]*(j-res);
f[i][j]+=f[i-1][j+1]*j;
f[i][j]%=mod;
}
}
cout << f[n][1] << '\n';
return 0;
}
T2:[JOI 2023 Final] Advertisement 2#
当我们做题遇到绝对值的时候,应该考虑将绝对值拆开,
那么,我们就可以化简一下这个式子,设
代码实现:
点击查看代码
struct node {
int x, y;
friend bool operator<(node x1, node x2) {
if (x1.x == x2.x)
return x1.y < x2.y;
return x1.x < x2.x;
}
}
a[500010];
int n, o, p, top;
int sta[500010];
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> o >> p;
a[i].x = o + p;
a[i].y = p - o;
}
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; i++) {
while (top && a[sta[top]].y <= a[i].y)
top--;
sta[++top] = i;
}
cout << top << '\n';
return 0;
}
T3:Your#
先考虑点的数量,题目说不存在三条及以上条的线过某一点,那么在⚪中四个点会有一个交点,所以交点的总数为
代码实现:
点击查看代码
#define int long long
using namespace std;
const int mod = 998244353;
int a, b, n, x, y;
int qpow(int a, int b) {
int res = 1;
while (b) {
if (b & 1)
res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
signed main() {
cin >> n;
x = qpow(24, mod - 2);
y = qpow(2, mod - 2);
a = (n % mod * (n - 1) % mod * (n - 2) % mod * (n - 3) % mod) % mod * x % mod;
b = (n % mod * (n - 1) % mod) % mod * y % mod;
cout << a % mod << '\n';
cout << (a + b + 1) % mod << '\n';
return 0;
}
CSP模拟22#
T1:The Child and Toy#
要求最后的答案值最小,考虑贪心,我们不难发现,删去一个点,其实就是删去和这个点相连的边,那么我们要想最终答案最小,就必须将点权小的边删去,大的留下,这样才能得出最优方案,所以我们直接在建边的时候删边,将两点之间较小的点权减去,加入答案中,最后输出答案即可。
代码实现:
点击查看代码
#define int long long
using namespace std;
int n, m, a, b, ans;
int val[1000010];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> val[i];
for (int i = 1; i <= m; i++) {
cin >> a >> b;
ans += min(val[a], val[b]);
}
cout << ans << '\n';
return 0;
}
CSP模拟25#
T1:[ARC128A] Gold and Silver#
考虑用 dp
转移,我们先去算出最后可以得到的最大的钱数,在 dp
的时候记录每一个值都是从哪里转移来的,最后递归输出答案即可。接下来想 dp
转移式,我们用 dp[i][j][k]
表示我们在第
代码实现:
点击查看代码
const int M=2e5+10;
int n,num;
double a[M],b[M];
int ro[M],rt[M],rs[M],rf[M],ans[M];
double f[M][2][2];
void getans(int x,int p)
{
if (num<=0) return;
if (x && p)
{
ans[num]=x;
num--;
getans(ro[num+1],p^1);
}
if (x && !p)
{
ans[num]=x;
num--;
getans(rs[num+1],p^1);
}
if (!x && p)
{
ans[num]=x;
num--;
getans(rt[num+1],p);
}
if (!x && !p)
{
ans[num]=x;
num--;
getans(rf[num+1],p);
}
}
int main()
{
cin >> n;
for (int i=1;i<=n;i++)
{
cin >> a[i];a[i]=log(a[i]);
b[i]=a[i];
}
sort(a+1,a+1+n);
int len=unique(a+1,a+1+n)-a-1;
for (int i=1;i<=n;i++)
b[i]=lower_bound(a+1,a+len+1,b[i])-a;
f[0][0][0]=1;
for (int i=1;i<=n;i++)
{
if (f[i-1][0][0]>f[i-1][1][0]) ro[i]=0;
else ro[i]=1;
f[i][1][1]=max(f[i-1][0][0],f[i-1][1][0])+b[i];
if (f[i-1][0][1]>f[i-1][1][1]) rs[i]=0;
else rs[i]=1;
f[i][1][0]=max(f[i-1][0][1],f[i-1][1][1])-b[i];
if (f[i-1][0][1]>f[i-1][1][1]) rt[i]=0;
else rt[i]=1;
f[i][0][1]=max(f[i-1][0][1],f[i-1][1][1]);
if (f[i-1][0][0]>f[i-1][1][0]) rf[i]=0;
else rf[i]=1;
f[i][0][0]=max(f[i-1][0][0],f[i-1][1][0]);
}
num=n;
if (f[n][1][0]>f[n][0][0]) getans(1,0);
else getans(0,0);
for (int i=1;i<=n;i++)
cout << ans[i] << ' ';
cout << '\n';
return 0;
}
T2:Make N#
这道题首先应该分类讨论。你把它当做一道普通数学题去思考,你想让你最终的价格尽量小,那你就要让性价比高的放的次数最多,这是我们分别算出
第一种:
第二种:
第三种:就是
代码实现:
点击查看代码
int read()
{
int f(1),x(0);char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
return f*x;
}
void write(int x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
int n,a,b,x,y,z,ans,T;
signed main()
{
T=read();
while(T--)
{
ans=0;
n=read();a=read();b=read();x=read();y=read();z=read();
long double pja=y/a,pjb=z/b;
if (pja>pjb)
swap(pja,pjb),swap(a,b),swap(y,z);
if(x<=pja && x<=pjb)
{
ans=n*x;
}
else if(x<pjb && x>pja)
{
ans+=y*(n/a);
ans+=x*(n%a);
}
else
{
ans=1e18;
for (int i=0;i<=ceil(sqrt(n));i++)
{
int res=0,temp;
res+=y*i;temp=n-a*i;
if(temp<0) continue;
res+=z*(temp/b);
res+=x*(temp%b);
ans=min(ans,res);
}
for (int i=0;i<=sqrt(n);i++)
{
int res=0,temp;
res+=z*i;
temp=n-b*i;
if(temp<0) continue;
res+=y*(temp/a);
res+=x*(temp%a);
ans=min(ans,res);
}
}
write(ans);putchar('\n');
}
return 0;
}
CSP模拟26#
T1:[AGC031B] Reversi#
考场上一直在想这道题是不是应该找到什么通用规律去解,后来发现好像想不出来,然后就骗了 f[i]
表示枚举到第
if(c[i]==c[i-1]) f[i]=f[i-1];
如果不是这种情况,我们就要将当前石头和之前所有相同颜色的石头之间染上色,思考一下,我们可以直接加上据他最近的石头的位置的方案数,因为我们之前也是这样推过来的,所以这样就可以涵盖所有的新方案数,再传递一下 f[i-1]
即可,这一步具体可以看代码实现,应该挺好理解的……
代码实现:
点击查看代码
const int mod=1e9+7;
int n;
int c[5000010],now[5000010],pre[5000010],f[5000010];
int main()
{
// file("a.in");
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin >> n;
for(int i=1;i<=n;i++)
{
cin >> c[i];
pre[i]=now[c[i]];
now[c[i]]=i;
}
f[1]=1;
for(int i=2;i<=n;i++)
{
if(c[i]==c[i-1]) f[i]=f[i-1];
else f[i]=(f[pre[i]]+f[i-1])%mod;
}
cout << f[n]%mod << '\n';
return 0;
}
作者:Aewrxuk
出处:https://www.cnblogs.com/Aewrxuk/p/17644036.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)