提高组数学专题 1
提高组数学专题 1
T1 [CF1909F1] Small Permutation Problem (Easy Version)
将排列的每项
题目中
设一个
,说明这一行列空下了, ; ,说明要么在空下的 行或 列放,要么在 放, , 不变; ,说明必须在空下的 行和 列各放一个,则 ,然后 。
#include<bits/stdc++.h>
#define fw fwrite(obuf,p3-obuf,1,stdout)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) (p3-obuf<1<<20?(*p3++=(x)):(fw,p3=obuf,*p3++=(x)))
using namespace std;
char buf[1<<20],obuf[1<<20],*p1=buf,*p2=buf,*p3=obuf,str[20<<2];
int read(){
int x=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x;
}
template<typename T>
void write(T x,char sf='\n'){
if(x<0) putchar('-'),x=~x+1;
int top=0;
do str[top++]=x%10,x/=10;while(x);
while(top) putchar(str[--top]+48);
if(sf^'#') putchar(sf);
}
constexpr int MAXN=2e5+5,MOD=998244353;
int T,n,a[MAXN];
bool fool(){
for(int i=1;i<=n;++i) if(a[i]>i||a[i]-a[i-1]>2) return 1;
return 0;
}
int main(){
T=read();
while(T--){
n=read();
for(int i=1;i<=n;++i) a[i]=read();
if(a[n]^n||fool()){
write(0);
continue;
}
long long ans=1,k=0;
for(int i=1;i<=n;++i)
switch(a[i]-a[i-1]){
case 0: ++k; break;
case 1: ans=ans*(k<<1|1)%MOD; break;
default:ans=ans*k%MOD*k%MOD;--k; break;
}
write(ans);
}
return fw,0;
}
T2 [CF1909E] Multiple Lamps
这题的
但仔细一想就可以发现,这个类似素数筛一样的开灯规则使得如果挨个开灯,最后亮着的一定是完全平方数。而
于是此题原本
数据范围小了许多,我们可以暴力枚举状态。具体地,预处理
预处理复杂度是
#include<bits/stdc++.h>
#define fw fwrite(obuf,p3-obuf,1,stdout)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) (p3-obuf<1<<20?(*p3++=(x)):(fw,p3=obuf,*p3++=(x)))
using namespace std;
char buf[1<<20],obuf[1<<20],*p1=buf,*p2=buf,*p3=obuf,str[20<<2];
int read(){
int x=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x;
}
template<typename T>
void write(T x,char sf='\n'){
if(x<0) putchar('-'),x=~x+1;
int top=0;
do str[top++]=x%10,x/=10;while(x);
while(top) putchar(str[--top]+48);
if(sf^'#') putchar(sf);
}
constexpr int MAXN=2e5+5;
int T,n,m;
struct{
int x,y;
}a[MAXN];
vector<int>ans[20];
int main(){
for(int i=5,B;i<=19;++i){
B=1<<i;
for(int s=1,sta;s<B;++s){
sta=0;
for(int j=1;j<=i;++j){
if(!(s&(1<<(j-1)))) continue;
for(int k=j;k<=i;k+=j) sta^=1<<(k-1);
}
if(__builtin_popcount(sta)*5<=i) ans[i].emplace_back(s);
}
}
T=read();
while(T--){
n=read(),m=read();
for(int i=1;i<=m;++i) a[i]={read()-1,read()-1};
if(n<5){
write(-1);
continue;
}else if(n>19){
write(n);
for(int i=1;i<=n;++i) write(i,' ');
putchar('\n');
continue;
}
for(auto s:ans[n]){
for(int i=1;i<=m;++i) if(s&1<<a[i].x&&!(s&1<<a[i].y)) goto sht;
write(__builtin_popcount(s));
for(int j=0;j<n;++j) if(s&1<<j) write(j+1,' ');
putchar('\n');
goto byby;
sht:;
}
write(-1);
byby:;
}
return fw,0;
}
T3 [HAOI2017] 方案数
能转移当且仅当后者的
对于这种我们不好考虑 “不经过” 的问题,我们常见的 trick 是容斥。于是对于一点
然后考虑障碍点的情况。先将障碍点按字典序排序以保证无后效性。设
其中
至此,问题解决。
#include<bits/stdc++.h>
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define int long long
#define pc __builtin_popcountll
using namespace std;
char buf[1<<20],*p1=buf,*p2=buf;
int read(){
int x=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x;
}
constexpr int MAXN=1e4+5,MOD=998244353;
int n,m,r,o;
struct P{
int x,y,z;
int xx,yy,zz;
bool operator<(const P&b)const{
if(x^b.x) return x<b.x;
if(y^b.y) return y<b.y;
return z<b.z;
}
}a[MAXN];
int C[65][65];
void init(int n){
for(int i=0;i<=n;++i){
C[i][0]=C[i][i]=1;
for(int j=1;j<i;++j) C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
}
}
void add(int&x,int y){
x=x+y>=MOD?x+y-MOD:x+y;
}
int sub(int x,int y){
return x-y<0?x-y+MOD:x-y;
}
int dp[65][65][65],f[MAXN];
int to(int j,int i){
if((a[j].x&a[i].x)^a[j].x||(a[j].y&a[i].y)^a[j].y||(a[j].z&a[i].z)^a[j].z) return 0;
return dp[a[i].xx-a[j].xx][a[i].yy-a[j].yy][a[i].zz-a[j].zz];
}
signed main(){
n=read(),m=read(),r=read(),o=read();
for(int i=1;i<=o;++i){
a[i]={read(),read(),read(),0,0,0};
a[i].xx=pc(a[i].x),a[i].yy=pc(a[i].y),a[i].zz=pc(a[i].z);
}
a[++o]={n,m,r,pc(n),pc(m),pc(r)};
init(max({a[o].xx,a[o].yy,a[o].zz}));
dp[0][0][0]=1;
for(int i=0;i<=a[o].xx;++i)
for(int j=0;j<=a[o].yy;++j)
for(int k=0;k<=a[o].zz;++k){
for(int l=0;l<i;++l) add(dp[i][j][k],dp[l][j][k]*C[i][l]%MOD);
for(int l=0;l<j;++l) add(dp[i][j][k],dp[i][l][k]*C[j][l]%MOD);
for(int l=0;l<k;++l) add(dp[i][j][k],dp[i][j][l]*C[k][l]%MOD);
}
sort(a+1,a+o+1);
for(int i=1,tmp;i<=o;++i){
tmp=0;
for(int j=1;j<i;++j) add(tmp,f[j]*to(j,i)%MOD);
f[i]=sub(dp[a[i].xx][a[i].yy][a[i].zz],tmp);
}
printf("%lld\n",f[o]);
return 0;
}
T4 [CF1917E] Construct Matrix
奇妙的构造题。
首先
对于
对于
的矩形,然后
对于
之后回到第一种情况。
对于
#include<bits/stdc++.h>
#define fw fwrite(obuf,p3-obuf,1,stdout)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) (p3-obuf<1<<20?(*p3++=(x)):(fw,p3=obuf,*p3++=(x)))
using namespace std;
char buf[1<<20],obuf[1<<20],*p1=buf,*p2=buf,*p3=obuf;
int read(){
int x=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x;
}
int T,n,k,a[1005][1005];
void print(){
for(int i=1;i<=n;++i,putchar('\n'))
for(int j=1;j<=n;++j)
putchar(a[i][j]?'1':'0'),putchar(' ');
}
#define Yes() putchar('Y'),putchar('e'),putchar('s'),putchar('\n')
#define No() putchar('N'),putchar('o'),putchar('\n')
int main(){
T=read();
while(T--){
n=read(),k=read();
if(k&1){
No();
continue;
}
for(int i=1;i<=n;++i) memset(a[i],0,sizeof(int)*(n+5));
if(!k){
Yes();
print();
continue;
}else if(k==n*n){
Yes();
for(int i=1;i<=n;++i,putchar('\n'))
for(int j=1;j<=n;++j)
putchar('1'),putchar(' ');
continue;
}else if(k==2||k==n*n-2){
if(n==2){
a[1][1]=a[2][2]=1;
Yes();
print();
}else No();
continue;
}else if(k%4==0){
for(int i=1;i<=n;i+=2)
for(int j=1;j<=n;j+=2){
a[i][j]=a[i][j+1]=a[i+1][j]=a[i+1][j+1]=1;
k-=4;
if(!k) goto fu;
}
fu:;
Yes();
print();
continue;
}else if(6<=k&&k<=n*n-10&&k%4==2){
a[1][1]=a[1][2]=a[2][1]=a[2][3]=a[3][2]=a[3][3]=1;
k-=6;
for(int i=1;i<=n;i+=2)
for(int j=1;j<=n;j+=2){
if(i<=4&&j<=4) continue;
if(!k) goto fy;
a[i][j]=a[i][j+1]=a[i+1][j]=a[i+1][j+1]=1;
k-=4;
}
fy:;
Yes();
print();
continue;
}else if(k==n*n-6){
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
a[i][j]=1;
a[1][3]=a[1][4]=a[2][2]=a[2][4]=a[4][2]=a[4][3]=0;
Yes();
print();
continue;
}
}
return fw,0;
}
T5 [CF1891E] Brukhovich and Exams
首先修改一个数顶多能使答案
所以我们思路的第一步肯定是先操作一次能使答案
时,删除
此时还有一种能使答案一次性
剩下的都是删一个少一对的情况,无非就是首尾的连续的
#include<bits/stdc++.h>
#define fw fwrite(obuf,p3-obuf,1,stdout)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) (p3-obuf<1<<20?(*p3++=(x)):(fw,p3=obuf,*p3++=(x)))
using namespace std;
char buf[1<<20],obuf[1<<20],*p1=buf,*p2=buf,*p3=obuf,str[20<<2];
int read(){
int x=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x;
}
template<typename T>
void write(T x,char sf='\n'){
if(x<0) putchar('-'),x=~x+1;
int top=0;
do str[top++]=x%10,x/=10;while(x);
while(top)putchar(str[--top]+48);
if(sf^'#')putchar(sf);
}
constexpr int MAXN=1e5+5;
int T,n,k,a[MAXN],gd[MAXN],ans;
int s[MAXN],q[MAXN],top,len;
struct Y{
int s,c;
Y(int s,int c):s(s),c(c){}
bool operator<(const Y&x)const{
return c<x.c;
}
};
int main(){
T=read();
while(T--){
n=read(),k=read();
for(int i=1;i<=n;++i) a[i]=read();
a[n+1]=0;
ans=0;
for(int i=1;i<n;++i){
gd[i]=__gcd(a[i],a[i+1]);
if(gd[i]==1) ++ans;
}
for(int i=2;i<n;++i){
if(!k) break;
if(gd[i-1]==1&&gd[i]==1&&a[i-1]>1&&a[i+1]>1)
a[i]=0,ans-=2,gd[i-1]=gd[i]=0,--k;
}
if(!k){
write(ans);
continue;
}
int kl=0,kr=0;
if(a[1]==1){
kl=1;
while(kl<n&&a[kl+1]==1) ++kl;
}
if(kl==n){
write(n-k);
continue;
}
if(a[n]==1){
kr=1;
int r=n;
while(r>1&&a[r-1]==1) --r,++kr;
}
top=len=0;
for(int i=kl+2;i<=n-kr-1;++i){
if(a[i]==1){
if(!len)s[++top]=i,q[top]=++len;
else ++len,++q[top];
}else len=0;
}
priority_queue<Y>qu;
for(int i=1;i<=top;++i) qu.emplace(s[i],q[i]);
while(!qu.empty()){
if(!k) break;
int x=qu.top().s,len=qu.top().c;
qu.pop();
for(int i=x;i<=x+len-1;++i){
--k,a[i]=0;
if(!k) break;
}
}
for(int i=kl;i;--i){
if(!k) break;
a[i]=0,--k;
}
for(int i=n-kr+1;i<=n;++i){
if(!k) break;
a[i]=0,--k;
}
for(int i=1;i<n;++i){
if(!k) break;
if(__gcd(a[i],a[i+1])==1) a[i]=0,--k;
}
ans=0;
for(int i=1;i<n;++i) if(__gcd(a[i],a[i+1])==1) ++ans;
write(ans);
}
return fw,0;
}
注意细节问题!让 CF 评测一次很费时间。能让 @未来姚班zyl 说出细节有亿点多的题目。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效