CF1207
CF1207A
贪心+暴力分讨(看起来背包也行?)
相信大家都会 不细写了
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline
#define gc getchar
#define pc putchar
const int N=2e5+5;
const int M=1e8+5;
const int inf=0x3f3f3f3f;
const int mod=998244353;
const double eps=1e-8;
inl int read(){
int x=0,f=1;char c=gc();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return x*f;
}
inl void write(int x){
if(x<0){pc('-');x=-x;}
if(x>9)write(x/10);
pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int t,n,m,a[N],b,p,f,h,c;
signed main(){
t=read();
while(t--){
b=read();p=read();f=read();h=read();c=read();
if(b/2>=p+f)writel(p*h+f*c);
else{
if(h>c){
if(b/2<p)writel(b/2*h);
else writel(p*h+(b/2-p)*c);
}else{
if(b/2<f)writel(b/2*c);
else writel(f*c+(b/2-f)*h);
}
}
}
return 0;
}
CF1207B
这题不限制操作次数 这就变简单很多
考虑一个点能不能改 判一下矩形四个点即可
\(O(nm)\) 暴力枚举 看最后所有1的数量判断是否覆盖全
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline
#define gc getchar
#define pc putchar
const int N=2e5+5;
const int M=1e8+5;
const int inf=0x3f3f3f3f;
const int mod=998244353;
const double eps=1e-8;
inl int read(){
int x=0,f=1;char c=gc();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return x*f;
}
inl void write(int x){
if(x<0){pc('-');x=-x;}
if(x>9)write(x/10);
pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int t,n,m,a[55][55],vis[55][55],tot,ans;
vector<pair<int,int>>v;
signed main(){
n=read();m=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]=read();
tot+=a[i][j];
}
}
for(int i=1;i<n;i++){
for(int j=1;j<m;j++){
if(a[i][j]&&a[i][j+1]&&a[i+1][j]&&a[i+1][j+1]){
if(!vis[i][j])ans++,vis[i][j]=1;
if(!vis[i+1][j])ans++,vis[i+1][j]=1;
if(!vis[i][j+1])ans++,vis[i][j+1]=1;
if(!vis[i+1][j+1])ans++,vis[i+1][j+1]=1;
v.push_back({i,j});
}
}
}
if(ans^tot){puts("-1");return 0;}
writel(v.size());
for(auto i:v)
writei(i.first),writel(i.second);
return 0;
}
CF1207C
简单dp。
设 \(f_{i,0/1}\) 表示铺设到 \(i\) 管道 不提升/提升的最小花费
初始 \(f_{0,0}=b\ f_{0,1}=2b\) (最开始的柱子)
转移显然:
- 第 \(i\) 块/第 \(i+1\) 块通车( \(i+1\) 块需要提前提升)
- 不提升绝对不行 \(f_{i,0}=inf\)
- 提升分两种:
(1) \(i-1\) 不提升:\(f_{i,1}=f_{i-1,0}+2a+2b\)(两块管子+两节柱子)
(2) \(i-1\) 提升:\(f_{i,1}=f_{i-1,1}+a+2b\)(一块管子+两节柱子)
- 第 \(i\) 块/第 \(i+1\) 块均不通车
- 不提升:
(1) \(i-1\) 不提升:\(f_{i,1}=f_{i-1,0}+a+b\)
(2) \(i-1\) 提升:\(f_{i,1}=f_{i-1,1}+2a+b\) - 提升:
(1) \(i-1\) 不提升:\(f_{i,1}=f_{i-1,0}+2a+2b\)
(2) \(i-1\) 提升:\(f_{i,1}=f_{i-1,1}+a+2b\)
答案 \(f_{n,0}\)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline
#define int ll
#define gc getchar
#define pc putchar
const int N=2e5+5;
const int M=1e8+5;
const int inf=0x3f3f3f3f3f3f3f3f;
const int mod=998244353;
const double eps=1e-8;
inl int read(){
int x=0,f=1;char c=gc();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return x*f;
}
inl void write(int x){
if(x<0){pc('-');x=-x;}
if(x>9)write(x/10);
pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int t,n,m,a,b,f[N][2];
char c[N];
signed main(){
t=read();
while(t--){
n=read();a=read();b=read();
f[0][0]=b;f[0][1]=inf;
scanf("%s",c+1);
for(int i=1;i<=n;i++){
if(c[i]=='1'||c[i+1]=='1'){
f[i][0]=inf;
f[i][1]=min(f[i-1][0]+(a<<1)+(b<<1),f[i-1][1]+a+(b<<1));
}else{
f[i][0]=min(f[i-1][0]+a+b,f[i-1][1]+(a<<1)+b);
f[i][1]=min(f[i-1][0]+(a<<1)+(b<<1),f[i-1][1]+a+(b<<1));
}
}
writel(f[n][0]);
}
return 0;
}
CF1207D
容斥+计数。
好序列:仅看第一关键字或第二关键字都不按升序排序的序列。
求二元组全排列好序列数。
考虑容斥:\(ans=\) 全排列 \(n!\) -按第一维排序有序数量-按第二维排序有序数量+排序后两维都有序数量
显然 求按第一\二维排序有序数量 可以先排序
考虑这个序列:\(1\ 2\ 2\ 3\ 3\ 3\)
假如按第一\二维排序得到序列是这个 数量是几
显然 相同元素随便排 答案都满足 也就是每种元素数量的阶乘 乘起来 所以答案为 \(1!\times 2!\times 3!\)
代码实现可以用双指针 其他方法也行 阶乘可以预处理
那么 求排序后两维都有序数量:以第一维为第一关键字排序、第二维为第二关键字排序
先判第二维是否有序 无序说明 排序后两维都有序数量=0 直接输出
求方案数思路一样:双指针找出第一维元素一样区间 在区间内再次双指针找第二维一样区间 阶乘乘起来即可
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline
#define int ll
#define gc getchar
#define pc putchar
const int N=3e5+5;
const int M=1e8+5;
const int inf=0x3f3f3f3f3f3f3f3f;
const int mod=998244353;
const double eps=1e-8;
inl int read(){
int x=0,f=1;char c=gc();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return x*f;
}
inl void write(int x){
if(x<0){pc('-');x=-x;}
if(x>9)write(x/10);
pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int t,n,m,a[N],b[N],fac[N],res,ans;
struct node{
int a,b;
}e[N];
inl bool cmpa(node x,node y){return x.a<y.a;}
inl bool cmpb(node x,node y){return x.b<y.b;}
inl bool cmp(node x,node y){return x.a^y.a?x.a<y.a:x.b<y.b;}
signed main(){
n=read();fac[0]=fac[1]=1;
for(int i=2;i<=n;i++)fac[i]=fac[i-1]*i%mod;res=fac[n];
for(int i=1;i<=n;i++)e[i]={read(),read()};
sort(e+1,e+n+1,cmpa);
ans=1;
for(int l=1,r=1;r<=n;l=r+1,r++){
while(r+1<=n&&e[r+1].a==e[l].a)r++;
ans=ans*fac[r-l+1]%mod;
}
res=(res-ans+mod)%mod;
sort(e+1,e+n+1,cmpb);
ans=1;
for(int l=1,r=1;r<=n;l=r+1,r++){
while(r+1<=n&&e[r+1].b==e[l].b)r++;
ans=ans*fac[r-l+1]%mod;
}
res=(res-ans+mod)%mod;
sort(e+1,e+n+1,cmp);
for(int i=1;i<n;i++)
if(e[i].b>e[i+1].b){
writel(res);return 0;
}
ans=1;
for(int l=1,r=1;r<=n;l=r+1,r++){
while(r+1<=n&&e[r+1].a==e[l].a)r++;
for(int p=l,q=l;q<=r;p=q+1,q++){
while(q+1<=r&&e[q+1].b==e[p].b)q++;
ans=ans*fac[q-p+1]%mod;
}
}
res=(res+ans)%mod;
writel(res);
return 0;
}
CF1207E
交互题格式真烦人
考虑每个二进制位:因为他会在你输出的数里随机选一个 所以要求这些数这一位都相同答案才能确定
这个数最多14位 假如我们每次分别让前7位和后7位相同 刚好能确定这个数
而每次剩下7位 共 \(2^7=128\) 种数 刚好够100个
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline
#define int ll
#define gc getchar
#define pc putchar
const int N=3e5+5;
const int M=1e8+5;
const int inf=0x3f3f3f3f3f3f3f3f;
const int mod=998244353;
const double eps=1e-8;
inl int read(){
int x=0,f=1;char c=gc();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return x*f;
}
inl void write(int x){
if(x<0){pc('-');x=-x;}
if(x>9)write(x/10);
pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int t,n,m,a,b,ans;
signed main(){
a=0;
for(int i=0;i<=6;i++)a+=(1<<i);
printf("? ");
for(int j=1;j<=100;j++)
writei(a),a+=(1<<7);
puts("");
fflush(stdout);
b=read();
for(int i=0;i<=6;i++){
if((b>>i)&1)continue;
ans+=(1<<i);
}
a=0;
for(int i=7;i<=13;i++)a+=(1<<i);
printf("? ");
for(int j=1;j<=100;j++)
writei(a),a++;
puts("");
fflush(stdout);
b=read();
for(int i=7;i<=13;i++){
if((b>>i)&1)continue;
ans+=(1<<i);
}
printf("! ");writel(ans);
fflush(stdout);
return 0;
}
CF1207F
根号分治。
对于1操作 显然 \(O(1)\) 可以完成
而二操作 可以理解为将序列分成 \(\dfrac{n}{x}\) 段长为 \(x\) 的段 每段会有一个答案
那么答案数 \(cnt=\dfrac{n}{x}\)
我们发现 \(x>\sqrt n\quad cnt<\sqrt n\) 暴力做
而 \(x\le \sqrt n\quad cnt\ge\sqrt n\)
发现 \(x\) 很小 可以预处理 \(f_{i,j}\) 表示所有下标模 \(x\) 的结果为 \(y\) 的位置的值之和(就是询问的答案)
在(1)加操作 考虑会造成的贡献 枚举第一维模数\(i\) \(f_{i,x\bmod i}\ \text{+=}\ y\)
总时间复杂度 \(O(n\sqrt n)\)
( \(\sqrt n\) 不要随便取 我开始取的750 直接T飞)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline
#define int ll
#define gc getchar
#define pc putchar
const int N=5e5+5;
const int M=705;
const int inf=0x3f3f3f3f3f3f3f3f;
const int mod=998244353;
const double eps=1e-8;
inl int read(){
int x=0,f=1;char c=gc();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return x*f;
}
inl void write(int x){
if(x<0){pc('-');x=-x;}
if(x>9)write(x/10);
pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int t,n,m,q,op,a[N],f[M][M],x,y;
signed main(){
q=read();
while(q--){
op=read();x=read();y=read();
if(op==1){
a[x]+=y;
for(int i=1;i<=700;i++)f[i][x%i]+=y;
}
if(op==2){
if(x<=700){writel(f[x][y]);continue;}
int ans=0;
for(;y<=5e5;y+=x)ans+=a[y];
writel(ans);
}
}
return 0;
}
CF1207G
G题是AC自动机 我太菜了不会 学完了补上()