noip模拟10
T1
数组开小痛失 \(30pts\) ...
\(60pts\) 做法:
按题目要求中 \((a,b,x,y)\) 的定义
预处理出 \(Pre_{i,j}\) 表示 \((1,1,i,j)\) 矩形的大小
容易推得
\((x,y,a,b)=(k+pre[a][b]-pre[x-1][b]-pre[a][y-1]+pre[x-1][y-1])mod(k)\)
对于\(n*m<=300\)的直接暴力枚举左上右下点求得个数,得 \(60pts\)
\(75pts\) :
在 \(60pts\) 的基础上,注意到有全部相等的特殊性质,故直接\(n*m\)枚举矩形的形状,符合条件的直接加上这种形状矩形的个数即可(注意开\(longlong\)
\(100pts\) :
开一个大小为 \(k\) 的 \(cnt\) 数组表示有多少个从第一列开始的矩形的和在膜 \(k\) 意义下等于 \(cnt_{i}\) 。
先枚举上边界在枚举下边界再从左往右递推即可,用栈清空节约时间。
Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
namespace EMT{
#define int long long
inline long long read(){long long x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
#define pf printf
#define F(i,a,b) for(register int i=a;i<=b;i++)
#define D(i,a,b) for(register int i=a;i>=b;i--)
inline void file(){
freopen("in.in","r",stdin);
freopen("my.out","w",stdout);
}
const int N=410;int n,m,k;
typedef long long ll;
inline bool is(ll x){return k*(x/k)==x;}
inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
int pre[N][N],ls[N];ll ans,cnt[1000100];std::stack<int>s;
inline int sum(int x,int y,int a,int b){
return (k+pre[a][b]-pre[x-1][b]-pre[a][y-1]+pre[x-1][y-1])%k;
}
inline short main(){
int c=1,ls=0;
n=read(),m=read(),k=read();
F(i,1,n)F(j,1,m){int x=read();if(ls&&ls!=x)c=0;ls=x;pre[i][j]=((ll)pre[i][j-1]+x)%k;}
F(i,2,n)F(j,1,m)pre[i][j]=((ll)pre[i][j]+pre[i-1][j])%k;
if(c){
F(i,1,n)F(j,1,m)if(is(pre[i][j]))ans+=(ll)(n-i+1)*(m-j+1);
pi(ans);return 0;
}
F(i,1,n){
F(j,i,n){
int t;while(!s.empty()){int x=s.top();s.pop();cnt[x]=0;}
cnt[0]=1;
F(l,1,m){
t=sum(i,1,j,l);s.push(t);
ans+=cnt[t];++cnt[t];
}
}
}
pi(ans);
return 0;
}
}
signed main(){return EMT::main();}
T2
还是 \(wtcl\),推了一整节考试没推出来 \(dp\) 式子...
既然不会 \(dp\) ,那就贪心。
将深度大的点排在前面,将它的 \(k\) 级父亲点亮是最优的,如果这个点已经标记过了,就可以直接跳过。
我们规定一个函数 \(out\) 来标记符合条件的点, \(dfs\) 求出每个点的深度,用结构体存储深度和编号,排序,并利用倍增函数 \(getfa\) 找 \(k\) 级父亲即可。
Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
namespace EMT{
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
#define pf printf
#define F(i,a,b) for(register int i=a;i<=b;i++)
#define D(i,a,b) for(register int i=a;i>=b;i--)
inline void file(){
freopen("in.in","r",stdin);
freopen("my.out","w",stdout);
}
const int N=1e5+100;int head[N],co;int n,k;struct node{int next,to;}e[N<<1];
inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
inline void add(int next,int to){e[++co].next=head[next],e[co].to=to;head[next]=co;}
bool light[N];
int deep[N],fa[N][22];
struct tree{
int dep,id;
bool operator<(const tree &a)const{return dep>a.dep;}
}t[N];
inline void out(int x,int dep,int fa){
light[x]=1;if(dep==k)return;
for(register int i=head[x];i;i=e[i].next){
int j=e[i].to;if(j==fa)continue;
out(j,dep+1,x);
}
}
inline void dfs(int x,int f){
t[x].id=x;
for(register int i=head[x];i;i=e[i].next){
int j=e[i].to;if(j==f)continue;
deep[j]=deep[x]+1;t[j].dep=deep[j];
fa[j][0]=x;for(register int i=1;(1<<i)<=deep[j];i++)fa[j][i]=fa[fa[j][i-1]][i-1];
dfs(j,x);
}
}
inline int getfa(int x,int k){
if(k>=deep[x])return 1;
D(i,20,0)if((1<<i)<=k){x=fa[x][i];k-=(1<<i);}
return x;
}
inline short main(){
//file();
n=read();k=read();read();
F(i,1,n-1){
int x=read(),y=read();
add(x,y);add(y,x);
}
dfs(1,0);
std::sort(t+1,t+n+1);
int cnt=0;
F(i,1,n){
if(light[t[i].id])continue;
int fa=getfa(t[i].id,k);
out(fa,0,0);cnt++;
}
pi(cnt);
return 0;
}
}
signed main(){return EMT::main();}
T3
利用差分数组和bfs来求得消除\(i,j\)的最小花费\(cost_{i,j}\)
最后再利用\(bfs\)节约点时间求得最小步数即可。
Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
namespace EMT{
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
#define pf printf
#define F(i,a,b) for(register int i=a;i<=b;i++)
#define D(i,a,b) for(register int i=a;i>=b;i--)
inline void file(){
freopen("in.in","r",stdin);
freopen("my.out","w",stdout);
}
const int N=4e5+100,maxn=0x3f3f3f3f;std::queue<int>q;
inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
int n,m,k,op[41],cnt,a[40],b[40],c[N],dis[N],cost[40][40];
const int M=1<<17;int f[M];bool v[M];
inline void bfs(int x){
memset(dis,0x3f,sizeof(dis));
q.push(op[x]);dis[op[x]]=0;
while(!q.empty()){
int u=q.front();q.pop();
F(i,1,m){
int l=u-b[i],r=u+b[i];
if(l>=1&&dis[l]==maxn){
dis[l]=dis[u]+1;
q.push(l);
}
if(r<=1+n&&dis[r]==maxn){
dis[r]=dis[u]+1;
q.push(r);
}
}
}
F(i,1,cnt){
if(dis[op[i]]!=maxn){
cost[x][i]=dis[op[i]];
}
}
}
inline int min(int a,int b){return a<b?a:b;}
inline short main(){
n=read();k=read();m=read();
F(i,1,k)a[i]=read(),c[a[i]]^=1,c[a[i]+1]^=1;
F(i,1,m)b[i]=read();
F(i,1,n+1)if(c[i])op[++cnt]=i;
memset(cost,0x3f,sizeof(cost));
memset(f,0x3f,sizeof(f));
F(i,1,cnt)bfs(i);
int st=(1<<cnt)-1;
f[st]=0;
q.push(st);
while(!q.empty()){
int i=q.front();q.pop();
F(j,1,cnt){
if(!(i&(1<<(j-1))))continue;
F(t,j+1,cnt){
if(!(i&(1<<(t-1))))continue;
int x=~(~(i)|(1<<(j-1))|(1<<(t-1)));
f[x]=min(f[x],f[i]+cost[j][t]);
if(!v[x])q.push(x),v[x]=1;
}
}
}
pi(f[0]);pn();
return 0;
}
}
signed main(){return EMT::main();}
Everything that kills me makes me feel alive.