NOIP提高组
NOIP提高组
2011
铺地毯
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int n,x,y;
bool bz=1;
int a[N],b[N],g[N],j[N];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d %d %d %d",&a[i],&b[i],&g[i],&j[i]);
g[i]+=a[i];j[i]+=b[i];
}
int x,y;
scanf("%d %d",&x,&y);
for(int i=n;i>=1;i--)
{
if((x>=a[i])&&(x<=g[i])&&(y>=b[i])&&(y<=j[i])) {cout<<i;return 0;}
}
cout<<-1;
return 0;
}
选择客栈
#include<bits/stdc++.h>
using namespace std;
#define N 200005
int n,m,ans,p,pos;
int sum[N],pre[N],col[55];
int main()
{
scanf("%d %d %d",&n,&m,&p);
for(int i=1,x,y;i<=n;++i)
{
scanf("%d %d",&x,&y);
++x;
pre[i]=col[x];
col[x]=i;
sum[i]=sum[pre[i]]+1;
if(y<=p) pos=i;
for(int j=pre[i];j;j=pre[j])
if(j<=pos)
{
ans+=sum[j];
break;
}
}
printf("%d",ans);
}
Mayan游戏
#include<bits/stdc++.h>
using namespace std;
#define FF for(int i=1;i<=5;++i) for(int j=1;j<=8;++j)
int n,mp[10][10],cp[10][10][10],ans[10][5];
bool vis[10][10];
bool pd()//判断消除
{
int ff=0;
FF if(mp[i][j])
{
if(i>1&&i<5&&mp[i][j]&&mp[i-1][j]==mp[i][j]&&mp[i+1][j]==mp[i][j])
ff=1,vis[i][j]=vis[i-1][j]=vis[i+1][j]=1;
if(j>1&&j<7&&mp[i][j]&&mp[i][j-1]==mp[i][j]&&mp[i][j+1]==mp[i][j])
ff=1,vis[i][j]=vis[i][j-1]=vis[i][j+1]=1;
}
FF if(vis[i][j]) vis[i][j]=mp[i][j]=0;
return ff;
}
void update()//更新图
{
mp[1][0]=mp[2][0]=mp[3][0]=mp[4][0]=mp[5][0]=0;
FF if(mp[i][j]) swap(mp[i][++mp[i][0]],mp[i][j]);
}
void dfs(int x);
void work(int i,int j,int k,int x)//操作一下
{
if(i+k<1||i+k>5||(k==-1&&mp[i+k][j]>0)) return;
swap(mp[i][j],mp[i+k][j]);
update();while(pd()) update();
ans[x][1]=i-1;ans[x][2]=j-1;ans[x][3]=k;
dfs(x+1);
memcpy(mp,cp[x],sizeof(cp[x]));
}
bool check(){for(int i=1;i<=5;++i) if(mp[i][1]) return 0;return 1;}
void dfs(int x)
{
if(check())
{for(int i=1;i<x;++i) printf("%d %d %d\n",ans[i][1],ans[i][2],ans[i][3]);exit(0);}
if(x==n+1) return;
memcpy(cp[x],mp,sizeof(mp));
FF if(mp[i][j]) work(i,j,1,x),work(i,j,-1,x);
}
int main()
{
scanf("%d",&n);
FF {scanf("%d",&mp[i][j]);if(!mp[i][j]) break;}
dfs(1);printf("-1");
}
计算系数
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=10007;
inline int quick(int a,int b)
{
int res=1;
a%=mod;
while(b)
{
if(b&1) res=(res*a)%mod;
b>>=1;
a=(a*a)%mod;
}
return res;
}
inline int jc(int x)
{
int res=1;
for(int i=1;i<=x;++i) res=(res*i)%mod;
return res;
}
inline int ny(int x)
{
return quick(x,mod-2);
}
inline int C(int k,int n)
{
return jc(n)*ny(jc(k))*ny(jc(n-k))%mod;
}
signed main()
{
int a,b,k,n,m;
cin>>a>>b>>k>>n>>m;
printf("%lld",C(n,k)*quick(a,n)*quick(b,m)%mod);
}
聪明的质监员
在\(i-j\)的范围内查询\(w\)大于等于\(W\)的的个数与对应的\(v\)的和:及区间套区间的查询,那肯定能想到主席树了。而且\(W\)值是一个不确定的值,所以二分。
主席树部分直接套模板,不会主席树的可以百度一下学一学,是很有用的一个数据结构!下面直接讲二分的部分。
题中取一个\(W\),在每个区间里查询到对应的所求值的和\(sum\),求\(|sum-S|\)的最小值。
\(1.\)二分的判断。
因为每次计算的时候,其实求的是大于等于\(W\)的所有数,所以\(W\)越小时\(sum\)越大。那么如果把所有的\(W\)从小到大排序,得到的对应的\(sum\)就是一个不标准的递减序列,在这个序列上找\(S\)的位置x时,就有:
如果\(sum[i]<S\),那么\(i>x\)。
如果\(sum[i]>S\),那么\(i<x\)。
如果\(sum[i]==S\),那么\(i=x\)。
\(2.\)二分的枚举。
由于主席树实质是套了一个权值线段树,在本题中就是以\(w\)的值做权值线段树的下标(为了节俭空间当然少不了离散化操作,所以下标实际上是\(w\)离散化后的值)。那么假设\(x,y\)都存在于\(w\)数组间,且\(x,y\)之间的数都不在\(w\)数组间,那么\(W\)取\(k∈[x+1,y]\)时,得到的\(sum\)值其实是一样的。只有当\(W\)取到\(x\)时,得到的\(sum\)才有可能变化。
而且本题并不需要求W的值,所以就可以直接抛开\(W\),直接将本题变成在权值线段树上任取一个区间\([k,n](k∈[1,n]),(n\)是离散化后对应的最大的下标\()\),使求出的\(|sum-S|\)的最小。
那么二分时直接二分权值线段树的下标即可。
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e5+5;
//权值线段树下标:w
int n,m,w[N],s[N];
int lx[N],rx[N],id[1000005];
int tt,root[N],lc[N<<5],rc[N<<5];
ll S,C,V,v[N],cnt[N<<5],val[N<<5];
void insert(int l,int r,int x,ll y,int p1,int &p2)
{
p2=++tt;
cnt[p2]=cnt[p1]+1;
val[p2]=val[p1]+y;
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) insert(l,mid,x,y,lc[p1],lc[p2]),rc[p2]=rc[p1];
else insert(mid+1,r,x,y,rc[p1],rc[p2]),lc[p2]=lc[p1];
}
void ask(int l,int r,int x,int p1,int p2)
{
if(p1==p2) return;
if(l>=x)
{
C+=cnt[p2]-cnt[p1];
V+=val[p2]-val[p1];
return;
}
int mid=(l+r)>>1;
if(x<=mid) ask(l,mid,x,lc[p1],lc[p2]);
ask(mid+1,r,x,rc[p1],rc[p2]);
}
ll query()
{
int l=1,r=s[0];
ll ans=S,sum;
while(l<=r)
{
int mid=(l+r)>>1;
sum=0;
for(int i=1;i<=m;++i)
{
C=V=0;
ask(1,s[0],mid,root[lx[i]-1],root[rx[i]]);
sum+=C*V;
}
if(abs(sum-S)<ans) ans=abs(sum-S);
if(sum<S) r=mid-1;
else if(sum>S) l=mid+1;
else break;
}
return ans;
}
int main()
{
scanf("%d %d %lld",&n,&m,&S);
for(int i=1;i<=n;++i) scanf("%d %lld",&w[i],&v[i]),s[i]=w[i];
sort(s+1,s+n+1);
s[0]=unique(s+1,s+n+1)-s-1;
for(int i=1;i<=s[0];++i) id[s[i]]=i;
for(int i=1;i<=n;++i) insert(1,s[0],id[w[i]],v[i],root[i-1],root[i]);
for(int i=1;i<=m;++i) scanf("%d %d",&lx[i],&rx[i]);
printf("%lld",query());
}
观光公交
max_num=0;
for(register int i=2;i<=N;++i)
{
if(!D[i-1]) continue;
tmp_num=0;
for(register int j=i;j<=N;++j)
{
tmp_num+=Leave[j];
if(Arrive[j]<=Latest[j]) break;
}
if(tmp_num>max_num)
{
max_num=tmp_num;
max_pos=i;
}
}
记录下位置后,便可以对Arrive和D数组进行更新。更新方式与枚举区间方式类似,请自行体会。
D[max_pos-1]--;
for(register int i=max_pos;i<=N;++i)
{
Arrive[i]--;
if(Arrive[i]<Latest[i]) break;
}
将以上两段操作重复k次,便得到更新后的Arrive数组。根据每一个乘客旅行开始的时间和下车的景点,计算出ans即可。
标程如下:
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5;
int n,m,k,ans,last[N],D[N],DIS[N],num[N],sum[N];
int main()
{
scanf("%d %d %d",&n,&m,&k);
for(int i=2;i<=n;++i) scanf("%d",&D[i]);
for(int i=1,t,x,y;i<=m;++i) scanf("%d %d %d",&t,&x,&y),last[x]=max(last[x],t),ans-=t,num[y]++;
for(int i=2;i<=n;++i) DIS[i]=max(last[i-1],DIS[i-1])+D[i];
while(k--)
{
for(int i=n;i;--i) sum[i]=DIS[i]>last[i]?num[i]+sum[i+1]:num[i];
int j=0;
for(int i=1;i<=n;++i) if(sum[i]>sum[j]&&D[i]>0) j=i;
D[j]--;
for(int i=j;i<=n;++i) DIS[i]=max(last[i-1],DIS[i-1])+D[i];
}
for(int i=1;i<=n;++i) ans+=DIS[i]*num[i];
cout<<ans;
}
2012
P1079 Vigenère 密码
#include <iostream>
using namespace std;
int main()
{
string k,c;
cin>>k>>c;
for (int i=0;i<c.length();i++) {
int t=(k[i%k.length()]&31)-1;
c[i]=(c[i]&31)-t>0?c[i]-t:c[i]-t+26;
}
cout<<c<<endl;
return 0;
}
P1080 国王游戏
#include <bits/stdc++.h>
using namespace std;
int now[20010],sum[20010],ans[20010],add[20010];
struct Node {
int a;
int b;
long long a_b;
}node[1010];
int read() {
int ans=0,flag=1;
char ch=getchar();
while( (ch>'9' || ch<'0') && ch!='-' ) ch=getchar();
if(ch=='-') flag=-1,ch=getchar();
while(ch>='0' && ch<='9') ans=ans*10+ch-'0',ch=getchar();
return ans*flag;
}
void times(int x) {
memset(add,0,sizeof(add));
for(int i=1;i<=ans[0];i++) {
ans[i]=ans[i]*x;
add[i+1]+=ans[i]/10;
ans[i]%=10;
}
for(int i=1;i<=ans[0]+4;i++) {
ans[i]+=add[i];
if(ans[i]>=10) {
ans[i+1]+=ans[i]/10;
ans[i]%=10;
}
if(ans[i]!=0) {
ans[0]=max(ans[0],i);
}
}
return ;
}
int divition(int x) {
memset(add,0,sizeof(add));
int q=0;
for(int i=ans[0];i>=1;i--) {
q*=10;
q+=ans[i];
add[i]=q/x;
if(add[0]==0 && add[i]!=0) {
add[0]=i;
}
q%=x;
}
return 0;
}
bool compare() {
if(sum[0]==add[0]) {
for(int i=add[0];i>=1;i--) {
if(add[i]>sum[i]) return 1;
if(add[i]<sum[i]) return 0;
}
}
if(add[0]>sum[0]) return 1;
if(add[0]<sum[0]) return 0;
}
void cp () {
memset(sum,0,sizeof(sum));
for(int i=add[0];i>=0;i--) {
sum[i]=add[i];
}
return ;
}
bool cmp(Node a,Node b) {
return a.a_b<b.a_b;
}
int main() {
int n=read();
for(int i=0;i<=n;i++) {
node[i].a=read(),node[i].b=read();
node[i].a_b=node[i].a*node[i].b;
}
sort(node+1,node+n+1,cmp);
ans[0]=1,ans[1]=1;
for(int i=1;i<=n;i++) {
times(node[i-1].a);
divition(node[i].b);
if(compare()) {
cp();
}
}
for(int i=sum[0];i>=1;i--)
printf("%d",sum[i]);
return 0;
}
P1081 开车旅行
#include<bits/stdc++.h>
using namespace std;
int n,h[1000005],ans=1;bool con;
int main()
{
cin>>n;for(int i=1;i<=n;i++) cin>>h[i];
if(h[2]>=h[1]) con=1;
for(int i=1;i<=n;i++)
{
if(con==0&&i==n) {ans++;break;}
if(con==1) if(h[i+1]<h[i]){ans++;con=0;continue;}
if(con==0) if(h[i+1]>h[i]) {ans++;con=1;continue;}
}
cout<<ans;
}
P1965 转圈游戏
#include<bits/stdc++.h>
using namespace std;
int n,m,k,x;
int quick(int a,int b)
{
int res=1;
a%=n;
while(b)
{
if(b&1) res=(res*a)%n;
b>>=1;
a=(a*a)%n;
}
return res;
}
int main()
{
cin>>n>>m>>k>>x;
int d=quick(10,k);
printf("%d",(x+m*d)%n);
}
P1966 火柴排队
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,mod=1e8-3;
int n,ans,a[N],b[N],id[N],c[N];
inline void add(int x){for(;x<=n;x+=x&-x) c[x]++;}
inline int ask(int x)
{
int res=0;
for(;x;x-=x&-x) res+=c[x];
return res;
}
inline bool cmp(int x,int y){return a[x]<a[y];}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]),b[i]=i;
sort(b+1,b+n+1,cmp);
for(int i=1;i<=n;++i) id[i]=b[i];//记录编号
for(int i=1;i<=n;++i) scanf("%d",&a[i]),b[i]=i;
sort(b+1,b+n+1,cmp);
for(int i=1;i<=n;++i) a[b[i]]=id[i];//离散化
for(int i=n;i;--i)
{
ans=(ans+ask(a[i]-1))%mod;
add(a[i]);
}
printf("%d",ans);
}
P1967 货车运输
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define MAXN 10005
#define INF 999999999
using namespace std;
struct Edge1{
int x,y,dis;
}edge1[50005]; //题目所给的图
struct Edge2{
int to,next,w;
}edge2[100005]; //最大生成树的图
int cnt,n,m,head[MAXN],deep[MAXN],f[MAXN],fa[MAXN][21],w[MAXN][21];
//f数组表示并查集中的父节点,fa数组表示树上的父节点,w数组表示最大载重
bool vis[MAXN];
void addedge(int from, int to, int w)
{ //前向星存图
edge2[++cnt].next=head[from];
edge2[cnt].to=to;
edge2[cnt].w=w;
head[from]=cnt;
return ;
}
bool CMP(Edge1 x, Edge1 y)
{
return x.dis>y.dis; //将边权从大到小排序
}
int find(int x){ //并查集寻找父节点
if(f[x]!=x) f[x]=find(f[x]);
return f[x];
}
void kruskal()
{
sort(edge1+1, edge1+m+1, CMP);
for(int i=1; i<=n; i++)
f[i]=i; //并查集初始化
for(int i=1; i<=m; i++)
if(find(edge1[i].x)!=find(edge1[i].y)){
f[find(edge1[i].x)]=find(edge1[i].y);
addedge(edge1[i].x, edge1[i].y, edge1[i].dis);
addedge(edge1[i].y, edge1[i].x, edge1[i].dis); //无向图,双向加边
}
return ;
}
void dfs(int node)
{
vis[node]=true;
for(int i=head[node]; i; i=edge2[i].next){ //前向星遍历
int to=edge2[i].to;
if(vis[to]) continue;
deep[to]=deep[node]+1; //计算深度
fa[to][0]=node; //储存父节点
w[to][0]=edge2[i].w; //储存到父节点的权值
dfs(to);
}
return ;
}
int lca(int x, int y)
{
if(find(x)!=find(y)) return -1; //不连通,输出-1
int ans=INF;
if(deep[x]>deep[y]) swap(x,y); //保证y节点更深
//将y节点上提到于x节点相同深度
for(int i=20; i>=0; i--)
if(deep[fa[y][i]]>=deep[x]){
ans=min(ans, w[y][i]); //更新最大载重(最小边权)
y=fa[y][i]; //修改y位置
}
if(x==y) return ans; //如果位置已经相等,直接返回答案
//寻找公共祖先
for(int i=20; i>=0; i--)
if(fa[x][i]!=fa[y][i]){
ans=min(ans, min(w[x][i], w[y][i])); //更新最大载重(最小边权)
x=fa[x][i];
y=fa[y][i]; //修改x,y位置
}
ans=min(ans, min(w[x][0], w[y][0]));
//更新此时x,y到公共祖先最大载重,fa[x][0], fa[y][0]即为公共祖先
return ans;
}
int main()
{
int x,y,z,q;
scanf("%d%d",&n,&m);
for(int i=1; i<=m; i++){
scanf("%d%d%d",&x,&y,&z);
edge1[i].x=x;
edge1[i].y=y;
edge1[i].dis=z;
} //储存题目所给图
kruskal();
for(int i=1; i<=n; i++)
if(!vis[i]){ //dfs收集信息
deep[i]=1;
dfs(i);
fa[i][0]=i;
w[i][0]=INF;
}
//LCA初始化
for(int i=1; i<=20; i++)
for(int j=1; j<=n; j++){
fa[j][i]=fa[fa[j][i-1]][i-1];
w[j][i]=min(w[j][i-1], w[fa[j][i-1]][i-1]);
}
scanf("%d",&q);
for(int i=1; i<=q; i++){
scanf("%d%d",&x,&y);
printf("%d\n",lca(x,y)); //回答询问
}
return 0;
}
P1979 华容道
#include<bits/stdc++.h>
using namespace std;
const int N=33,M=N*N*4;
int n,m,Q,EX,EY,SX,SY,TX,TY;//基本输入
int te,vv[M*3],ww[M*3],pre[M*3],tail[M];//边
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};//移动
int vis[N][N],D[N][N];//bfs
int DIS[M];bool vs[M];//图论
//01对应 23对应
inline int id(int x,int y){return x*N+y;}
inline int id_(int x,int y){return (x*N+y)<<2;}
inline void add(int u,int v,int w){++te;vv[te]=v;ww[te]=w;pre[te]=tail[u];tail[u]=te;}
void bfs(int ex,int ey,int sx,int sy,int k)
{
memset(D,-1,sizeof(D));
D[ex][ey]=0;
D[sx][sy]=1;
vector<int>q;
int l=0;
q.push_back(id(ex,ey));
while(l<q.size())
{
int x=q[l]/N,y=q[l]%N;++l;
for(int i=0;i<4;++i)
{
int xx=x+dx[i],yy=y+dy[i];
if(vis[xx][yy]&&D[xx][yy]==-1)
{
D[xx][yy]=D[x][y]+1;
q.push_back(id(xx,yy));
}
}
}
if(k==8) return;
int tmp=id_(sx,sy);
for(int i=0;i<4;++i)
{
int xx=sx+dx[i],yy=sy+dy[i];
if(D[xx][yy]>0)
{
add(tmp+k,tmp+i,D[xx][yy]);
}
}
add(tmp+k,id_(ex,ey)+(k^1),1);//交换位置状态翻转
}
void spfa()
{
deque<int>q;
memset(DIS,0x3f,sizeof(DIS));
int tmp=id_(SX,SY);
for(int i=0;i<4;++i)
{
int xx=SX+dx[i],yy=SY+dy[i];
if(D[xx][yy]!=-1) DIS[tmp+i]=D[xx][yy],q.push_back(tmp+i);
}
while(!q.empty())
{
int u=q.front();
q.pop_front();
vs[u]=0;
for(int i=tail[u];i;i=pre[i])
{
int v=vv[i],w=ww[i];
if(DIS[v]>DIS[u]+w)
{
DIS[v]=DIS[u]+w;
if(vs[v]==0)
{
vs[v]=1;
if(q.empty()||D[v]>D[q.front()]) q.push_back(v);
else q.push_back(v);
}
}
}
}
}
int main()
{
scanf("%d %d %d",&n,&m,&Q);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%d",&vis[i][j]);
//预处理所有边
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(vis[i][j])
{
for(int k=0;k<4;++k)
{
int xx=i+dx[k],yy=j+dy[k];
if(vis[xx][yy]) bfs(xx,yy,i,j,k);
}
}
while(Q--)
{
scanf("%d %d %d %d %d %d",&EX,&EY,&SX,&SY,&TX,&TY);
if(SX==TX&&SY==TY)
{
printf("0\n");
continue;
}
bfs(EX,EY,SX,SY,8);//空格到所有格子的位置
spfa();
int ans=DIS[0],tmp=id_(TX,TY);
for(int i=0;i<4;++i) ans=min(ans,DIS[tmp+i]);
printf("%d\n",(ans==DIS[0])?-1:ans);
}
}
/*
id:(i*N+j)*4+0~3
状态转移:x:指定的棋子 e:空格子
.e. ... | ... | ... | .ex
.x.-->.xe | ex. | .x. | .e.
... ... | ... | .e. | ...
空格子换到另外三个地方或者进行棋子的走动
x向四方移动的前提是空格移动到四方,所以求出当格子到一方时到另外三方或者直接进行移动的步数。
求前者是因为每次询问时都会先将空格子移动到指定格子的四方,但具体哪一方并不确定。
BFS:空格子到所有格子的距离
SPFA:四种状态的起点到终点的距离
*/
2014
P2038 无线网络发射器选址
一看题,哎呀,二维树状数组||线段树||扫描线哎呀好麻烦喔,一看数据范围,呵呵,暴力了。
#include<bits/stdc++.h>
using namespace std;
const int N=25;
int d,n,sum,ans,cnt,x[25],y[25],z[25];
int main()
{
scanf("%d %d",&d,&n);
for(int i=1;i<=n;++i) scanf("%d %d %d",&x[i],&y[i],&z[i]);
for(int i=0;i<=128;++i)
for(int j=0;j<=128;++j)
{
cnt=0;
for(int k=1;k<=n;++k)
if(abs(i-x[k])<=d&&abs(j-y[k])<=d) cnt+=z[k];
if(cnt>ans) sum=1,ans=cnt;
else if(cnt==ans) sum++;
}
cout<<sum<<" "<<ans;
}
P1328 生活大爆炸版石头剪刀布
#include<bits/stdc++.h>
using namespace std;
const int N=205;
int n,na,nb,A[N],B[N],sa,sb;
bool bz[6][6];
int main()
{
bz[1][3]=bz[1][4]=1;
bz[2][1]=bz[2][4]=1;
bz[3][2]=bz[3][5]=1;
bz[4][3]=bz[4][5]=1;
bz[5][1]=bz[5][2]=1;
scanf("%d %d %d",&n,&na,&nb);
for(int i=0;i<na;++i) scanf("%d",&A[i]);
for(int i=0;i<nb;++i) scanf("%d",&B[i]);
for(int i=0;i<n;++i)
{
int x=A[i%na]+1,y=B[i%nb]+1;
sa+=bz[x][y];
sb+=bz[y][x];
}
cout<<sa<<" "<<sb<<"\n";
}
P1941 飞扬的小鸟
向上可以向上很多次,向下只能一次。
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5,M=1e3+5,INF=1e9;//INF=N
int n,m,q,v1[N],v2[N],F[2][N];
int tc=1,ff=1;//统计穿过多少管道
struct C_
{
int x,l,r;
friend bool operator<(C_ a,C_ b)
{
return a.x<b.x;
}
}C[N];
int main()
{
scanf("%d %d %d",&n,&m,&q);
for(int i=1;i<=n;++i) scanf("%d %d",&v1[i],&v2[i]);
for(int i=1;i<=q;++i) scanf("%d %d %d",&C[i].x,&C[i].l,&C[i].r);
sort(C+1,C+q+1);
F[1][0]=F[0][0]=INF;
int I,cnt,last,V;
for(int i=1;i<=n;++i)
{
I=i%2;
F[I][m]=INF;
for(int j=1;j<=v1[i];++j)
{
last=0;
for(int s=j;s<m;s+=v1[i])
{
V=F[I^1][last]+(s-last)/v1[i];
F[I][s]=min(INF,V);
if(s+v2[i]<=m) F[I][s]=min(F[I][s],F[I^1][s+v2[i]]);
if(F[I^1][s]!=INF&&F[I^1][s]<V) last=s;
}
F[I][m]=min(F[I][m],F[I^1][last]+(m-last)/v1[i]+((m-last)%v1[i]!=0));
}
F[I][m] = min(F[I][m], F[I ^ 1][m] + 1);
if(tc<=q&&i==C[tc].x)
{
cnt=0;
for(int j=1;j<=m;++j)
if(j<=C[tc].l||j>=C[tc].r) F[I][j]=INF;
else cnt+=(F[I][j]!=INF);
if(cnt==0)
{
printf("0\n%d",tc-1);
return 0;
}
else tc++;
}
}
cnt=INF;
I=n%2;
for(int i=1;i<=m;++i) cnt=min(F[I][i],cnt);
if(cnt==INF) printf("0\n%d",tc-1);
else printf("1\n%d",cnt);
}
P2296 寻找道路
给定一张有向图,给定限定条件,不满足条件的点不可走,问st到ed是否连通,若连通求最短路长度。
建反图处理限定条件,如果ed可以到x,那么反图与x相连的所有点y对应的正边都是满足条件的,则y不符合条件的出边-1。(一开始假定所有边都不满足条件)
SPFA跑最短路,记得判断st是否符合限定条件。
(一开始还以为是多次询问题,边读题边想如何处理多次条件,想都想好了一看,一次性问题,浪费感情!!!)
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5,M=2e5+5;
int n,m,st,ed,D[N],cnt[N];
int te,vv[M],pre[M],tail[N];
int fv[M],fpre[M],ftail[M];
bool cb[N][N],vis[N];
inline void add(int u,int v)
{
// cout<<"\nADD:"<<u<<" "<<v<<"\n";
te++;cnt[u]++;
vv[te]=v;pre[te]=tail[u];tail[u]=te;
fv[te]=u;fpre[te]=ftail[v];ftail[v]=te;
}
void bfs1()
{
vector<int>q;
vis[ed]=1;
q.push_back(ed);
int l=0;
while(l<q.size())
{
int u=q[l++];
for(int i=ftail[u];i;i=fpre[i])
{
int v=fv[i];
cnt[v]--;
if(!vis[v]) vis[v]=1,q.push_back(v);
}
}
}
int bfs2()
{
if(cnt[st]) return -1;
vector<int>q;
q.push_back(st);
D[st]=1;
int l=0;
while(l<q.size())
{
int u=q[l++];
for(int i=tail[u];i;i=pre[i])
{
int v=vv[i];
if(cnt[v]==0&&D[v]==0)
{
D[v]=D[u]+1;
q.push_back(v);
if(v==ed) return D[v]-1;
}
}
}
return -1;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1,u,v;i<=m;++i)
{
scanf("%d %d",&u,&v);
if(u==v||cb[u][v]) continue;
cb[u][v]=1;
add(u,v);
}
scanf("%d %d",&st,&ed);
bfs1();
printf("%d",bfs2());
}
P1351 联合权值
好水,真的好水,开始读题到AC只有十分钟。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e5+5,mod=10007;
int n;
int te,vv[N<<1],pre[N<<1],tail[N];
int Sum,Mx,val[N],sum[N],mx[N];
bool vis[N];
inline void add(int u,int v)
{
++te;vv[te]=v;pre[te]=tail[u];tail[u]=te;
}
void dfs(int u)
{
vis[u]=1;
for(int i=tail[u];i;i=pre[i])
{
int v=vv[i];
if(vis[v]) continue;
dfs(v);
Sum=(Sum+val[u]*sum[v]+sum[u]*val[v])%mod;sum[u]=(sum[u]+val[v])%mod;
Mx=max(Mx,max(val[u]*mx[v],mx[u]*val[v]));mx[u]=max(mx[u],val[v]);
}
}
int main()
{
scanf("%d",&n);
for(int i=1,u,v;i<n;++i) scanf("%d %d",&u,&v),add(u,v),add(v,u);
for(int i=1;i<=n;++i) scanf("%d",&val[i]);
dfs(1);
printf("%d %d",Mx,(Sum*2)%mod);
}
P2312 解方程
1.计算过大数据除了高精度外,还有一种方法:模大质数(比如\(1e9+7\))
2.秦九韶算法:
掌握以上两点本题就可以切掉了。
\(Tips:\)可以不模的地方就不要模,这就是是TLE到AC的差距。
\(res=(res*valo/omod+a[i])o/omod:80\)分
\(res=(res*val+a[i])o/omod:100\)分
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=105,M=1e6+5,mod=1e9+7;
int n,m,val,a[N],ans[M];
int read()
{
int res=0,w=1;
char dd=getchar();
while(dd<'0'||dd>'9') {if(dd=='-') w=-1;dd=getchar();}
while(dd>='0'&&dd<='9') {res=(res*10+dd-'0')%mod;dd=getchar();}
return res*w;
}
inline int query()
{
int res=0;
for(int i=n;i>=0;--i) res=(res*val+a[i])%mod;
return res;
}
signed main()
{
n=read();m=read();
for(int i=0;i<=n;++i) a[i]=read();
for(val=1;val<=m;++val)
if(query()==0) ans[++ans[0]]=val;
printf("%lld\n",ans[0]);
for(int i=1;i<=ans[0];++i) printf("%lld\n",ans[i]);
}
2015
P2615 神奇的幻方
#include<bits/stdc++.h>
using namespace std;
int n,ts[40][40],x,y;
int main()
{
scanf("%d",&n);
x=1;y=n/2+1;
ts[x][y]=1;
for(int i=2;i<=n*n;i++)
{
if(x==1&&y<n) {x=n;y++;}
else
if(x==1&&y==n) x++;
else
if(x!=1&&y==n) {x--;y=1;}
else
if(!ts[x-1][y+1]) {x--;y++;}
else x++;
// if(x==1)
// {
// if(y<n) x=n,y++;
// else x++;
// }
// else
// if(y==n) x--,y=1;
// else
// if(!ts[x-1][y+1]) x--,y++;
// else x++;
ts[x][y]=i;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
printf("%d ",ts[i][j]);
printf("\n");
}
return 0;
}
P2678 跳石头
#include<bits/stdc++.h>
using namespace std;
int n,m,k,now=0,l,r,mid,step,ans;
int tone[50005];
bool pd(int len)
{
now=0;step=0;
for(int i=1;i<=m+1;i++)
{
if(tone[i]-tone[now]>=len) now=i;
else step++;
}
if(step<=k) return 1;
return 0;
}
int main()
{
scanf("%d %d %d",&n,&m,&k);
for(int i=1;i<=m;i++)
scanf("%d",&tone[i]);
tone[m+1]=n;
l=0;r=n;mid=k;
while(l<r)
{
mid=(l+r+1)/2;
if(pd(mid)) l=ans=mid;
else r=mid-1;
}
printf("%d",ans);
}
P2661 信息传递
#include<bits/stdc++.h>
using namespace std;
#define op 200005
int n,ans;
int next[op],num[op];
bool bz1[op],bz2[op];
//bz1:走过
//bz2:走过并且状态已记录:不可连接或可连接
void dfs(int x,int y)
{
if(bz2[x]) return;
if(bz1[x]) ans=min(ans,y-num[x]);
else
{
bz1[x]=1;
num[x]=y;
dfs(next[x],y+1);
bz2[x]=1;
}
}
int main()
{
ans=2e9;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&next[i]);
for(int i=1;i<=n;i++)
dfs(i,0);
printf("%d",ans);
return 0;
}
P2679 子串
#include<iostream>
using namespace std;
long long f[201][201], sum[201][201], n, m, ki;
char a[1001], b[201];
int main(){
cin >> n >> m >> ki >> a >> b;
f[0][0] = 1;
for(int i = 1;i <= n; i++)
for(int j = m;j >= 1; j--)
for(int k = ki;k >= 1; k--)
f[j][k] = (f[j][k] + (sum[j][k] = a[i - 1] == b[j - 1] ? sum[j - 1][k] + f[j - 1][k - 1] : 0)) % 1000000007;
cout << f[m][ki];
return 0;
}
P2680 运输计划
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int n,m,te,tail[N],dep[N],sum[N],d[N],val[N],f[N][22];
struct e_
{
int v,w,pre;
}e[N<<1];
struct t_
{
int u,v,lca,dis;
friend bool operator<(t_ a,t_ b)
{
return a.dis>b.dis;
}
}t[N];
inline void read(int &x)
{
char dd=getchar();x=0;
while(dd<'0'||dd>'9') dd=getchar();
while(dd>='0'&&dd<='9') x=(x<<1)+(x<<3)+dd-'0',dd=getchar();
}
inline void add(int u,int v,int w)
{
e[++te]={v,w,tail[u]};
tail[u]=te;
}
void dfs1(int u)
{
for(int i=tail[u];i;i=e[i].pre)
{
int v=e[i].v,w=e[i].w;
if(v==f[u][0]) continue;
val[v]=w;
d[v]=d[u]+w;
dep[v]=dep[u]+1;
f[v][0]=u;
for(int j=1;(1<<j)<=dep[v]&&j<=20;++j) f[v][j]=f[f[v][j-1]][j-1];
dfs1(v);
}
}
int lca_(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
for(int j=20;j>=0;--j)
if(dep[v]+(1<<j)<=dep[u]) u=f[u][j];
if(u==v) return u;
for(int j=20;j>=0;--j)
if(f[u][j]!=f[v][j]) u=f[u][j],v=f[v][j];
return f[u][0];
}
void dfs2(int u)
{
for(int i=tail[u];i;i=e[i].pre)
{
int v=e[i].v;
if(v==f[u][0]) continue;
dfs2(v);
sum[u]+=sum[v];
}
}
bool check(int mid)
{
for(int i=1;i<=n;++i) sum[i]=0;
int cnt=0;
for(int i=1;i<=m;++i)
{
if(t[i].dis<=mid) break;
sum[t[i].u]++;
sum[t[i].v]++;
sum[t[i].lca]-=2;
cnt++;
}
dfs2(1);
for(int i=1;i<=n;++i)
if(sum[i]==cnt&&t[1].dis-val[i]<=mid) return 1;
return 0;
}
int main()
{
read(n);
read(m);
for(int i=1,u,v,w;i<n;++i) read(u),read(v),read(w),add(u,v,w),add(v,u,w);
dfs1(1);
for(int i=1,u,v;i<=m;++i)
{
read(t[i].u);
read(t[i].v);
t[i].lca=lca_(t[i].u,t[i].v);
t[i].dis=d[t[i].u]+d[t[i].v]-2*d[t[i].lca];
}
sort(t+1,t+m+1);
int l=0,r=t[1].dis;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid)) r=mid-1;
else l=mid+1;
}
printf("%d",r+1);
}
2016
P1563 玩具谜题
#include<bits/stdc++.h>
using namespace std;
string s[100005];
bool bz[100005];
int n,m,ans=0,a,b;
int main()
{
scanf("%d %d",&n,&m);
for(int i=0;i<n;i++)
{
scanf("%d",&bz[i]);
cin>>s[i];
}
for(int i=1;i<=m;i++)
{
scanf("%d %d",&a,&b);
if(bz[ans]==a)
ans=(ans+n-b)%n;
else ans=(ans+b)%n;
}
cout<<s[ans];
return 0;
}
P2822 组合数问题
#include<bits/stdc++.h>
using namespace std;
int a,b;
int f[2005][2005],num[2005][2005],t,k;
int input()
{
char tt;
int so=0;
while((tt=getchar())&&(tt>='0')&&(tt<='9'))
so=so*10+tt-'0';
return so;
}
void prepare()
{
f[0][0]=0;
f[1][0]=f[1][1]=1;
for(int i=2;i<=2000;i++)
{
f[i][0]=1;
for(int j=1;j<=2000;j++)
{
if(j<=i)
{
f[i][j]=(f[i-1][j-1]+f[i-1][j])%k;
if(j<i) num[i][j]=num[i][j-1]+num[i-1][j]-num[i-1][j-1];
else num[i][j]=num[i][j-1];
if(!f[i][j]) num[i][j]++;
}
if(j>i)
{
num[i][j]=num[i][j-1];
}
}
}
}
int main()
{
scanf("%d %d",&t,&k);
prepare();
while(t--)
{
scanf("%d %d",&a,&b);
printf("%d\n",num[a][b]);
}
}
P1850 换教室_pts84
#include<bits/stdc++.h>
using namespace std;
const int N=2005,M=305;
int n,m,v,e;
int a[N],b[N];
double ans=1e9,k[N],d[M][M],f[N][2];
int main()
{
scanf("%d %d %d %d",&n,&m,&v,&e);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=n;++i) scanf("%d",&b[i]);
for(int i=1;i<=n;++i) scanf("%lf",&k[i]);
for(int i=1;i<=v;++i)
for(int j=1;j<=v;++j)
d[i][j]=1e9;
for(int i=1;i<=v;++i) d[i][i]=d[i][0]=d[0][i]=0.0;
for(int i=1,u,v,x;i<=e;++i)
scanf("%d %d %d",&u,&v,&x),d[u][v]=d[v][u]=min(x*1.0,d[u][v]);
for(int k=1;k<=v;++k)
for(int i=1;i<=v;++i)
for(int j=1;j<=v;++j)
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
for(int j=0;j<=m;++j) f[j][0]=f[j][1]=1e9;
f[0][0]=0;f[1][1]=0;
for(int i=2;i<=n;++i)
{
double v00=d[a[i-1]][a[i]],
v10=(1-k[i-1])*d[a[i-1]][a[i]]+k[i-1]*d[b[i-1]][a[i]],
v01=(1-k[i])*d[a[i-1]][a[i]]+k[i]*d[a[i-1]][b[i]],
v11=(1-k[i-1])*((1-k[i])*d[a[i-1]][a[i]]+k[i]*d[a[i]][b[i]])
+k[i-1]*((1-k[i])*d[b[i-1]][a[i]]+k[i]*d[b[i-1]][b[i]]);
for(int j=m;j;--j)
f[j][0]=min(f[j][0]+v00,f[j][1]+v10),
f[j][1]=min(f[j-1][0]+v01,f[j-1][1]+v11);
f[0][0]=f[0][0]+v00;
}
for(int j=0;j<=m;++j) ans=min(ans,min(f[j][0],f[j][1]));
printf("%.2lf",ans);
}
P2827 蚯蚓
先分的一定大于后分的。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;
int n,m,x,u,v,t,now,val,len;
int a[N];
deque<int>b,c;
//p=u/v
//增加x的长度
bool cmp(int x,int y)
{
return x>y;
}
inline int max(int x,int y)
{
return x>y?x:y;
}
inline int get()
{
int res=a[a[0]];
if(!b.empty()) res=max(res,b.front());
if(!c.empty()) res=max(res,c.front());
if(res==a[a[0]]) a[0]++;
else if(!b.empty()&&res==b.front()) b.pop_front();
else c.pop_front();
return res+len;
}
signed main()
{
scanf("%lld %lld %lld %lld %lld %lld",&n,&m,&x,&u,&v,&t);
for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
sort(a+1,a+n+1,cmp);a[n+1]=-1e18;a[0]=1;
for(int i=1;i<=m;++i)
{
now=get();
len+=x;
val=now*u/v;
b.push_back(val-len);
c.push_back(now-val-len);
if(i%t==0) printf("%lld ",now);
}
printf("\n");n+=m;
for(int i=1;i<=n;++i)
{
now=get();
if(i%t==0) printf("%lld ",now);
}
}
P1600 天天爱跑步
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int n,m,te,w[N],d[N],ans[N],tail[N],f[N][22],c1[N*2],c2[N*2];
struct e_
{
int v,pre;
}e[N*2];
vector<int>a1[N],a2[N],b1[N],b2[N];
inline void add(int u,int v)
{
e[++te]=(e_){v,tail[u]};
tail[u]=te;
}
void dfs1(int u)
{
for(int i=tail[u];i;i=e[i].pre)
{
int v=e[i].v;
if(v==f[u][0]) continue;
d[v]=d[u]+1;
f[v][0]=u;
for(int j=1;(1<<j)<d[v];++j) f[v][j]=f[f[v][j-1]][j-1];
dfs1(v);
}
}
int lca_(int u,int v)
{
if(d[u]<d[v]) swap(u,v);
for(int j=20;j>=0;j--)
if(d[v]+(1<<j)<=d[u]) u=f[u][j];
if(u==v) return u;
for(int j=20;j>=0;j--)
if(f[u][j]!=f[v][j]) u=f[u][j],v=f[v][j];
return f[u][0];
}
void dfs2(int u)
{
int val=c1[d[u]+w[u]]+c2[d[u]-w[u]+n];
for(int i=tail[u];i;i=e[i].pre)
{
int v=e[i].v;
if(v==f[u][0]) continue;
dfs2(v);
}
for(int i=0;i<a1[u].size();++i) c1[a1[u][i]]++;
for(int i=0;i<b1[u].size();++i) c1[b1[u][i]]--;
for(int i=0;i<a2[u].size();++i) c2[a2[u][i]]++;
for(int i=0;i<b2[u].size();++i) c2[b2[u][i]]--;
ans[u]=c1[d[u]+w[u]]+c2[d[u]-w[u]+n]-val;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1,u,v;i<n;++i)
{
scanf("%d %d",&u,&v);
add(u,v);add(v,u);
}
for(int i=1;i<=n;++i) scanf("%d",&w[i]);
d[1]=1;
dfs1(1);
for(int i=1,u,v;i<=m;++i)
{
scanf("%d %d",&u,&v);
int lca=lca_(u,v);
a1[u].push_back(d[u]);
b1[f[lca][0]].push_back(d[u]);
a2[v].push_back(2*d[lca]-d[u]+n);
b2[lca].push_back(2*d[lca]-d[u]+n);
}
dfs2(1);
for(int i=1;i<=n;++i) printf("%d ",ans[i]);
}
2017
P3958 奶酪
#include<bits/stdc++.h>
using namespace std;//不加本代码爆零
int f[1001];//并查集
int find(int x){
if (x!=f[x]) f[x]=find(f[x]);
return f[x];
}//查找+路径压缩
long long dis(long long x,long long y,long long z,long long x1,long long y1,long long z1){
return (x-x1)*(x-x1)+(y-y1)*(y-y1)+(z-z1)*(z-z1);
}//两点距离公式,注意这里算的是距离平方。
long long x[100001],y[100001],z[100001];
int f1[100001],f2[100001];
//f1记录与顶面相交的洞的序号
//f2记录与底面相交的洞的序号
int main(){
int t;
scanf("%d",&t);
int n,h;
long long r;
for (int i=1;i<=t;i++){
scanf("%d%d%lld",&n,&h,&r);//long long不开的话...
int tot1=0;//记录与顶面相交的洞有几个
int tot2=0;//记录与底面相交的洞有几个
for (int j=1;j<=n;j++){
f[j]=j; //并查集初始化
}
for (int j=1;j<=n;j++){
scanf("%lld%lld%lld",&x[j],&y[j],&z[j]);//long long不开的话...
if (z[j]+r>=h){//判断这个点是否与顶面相交
tot1++;
f1[tot1]=j;
}
if (z[j]-r<=0){//判断这个点是否与底面相交
tot2++;
f2[tot2]=j;
}
for (int k=1;k<=j;k++){//枚举之前的洞是否与这个洞相交,如果相交则合并集合
if ((x[j]-x[k])*(x[j]-x[k])+(y[j]-y[k])*(y[j]-y[k])>4*r*r) continue;
//防止爆long long的特判。
if (dis(x[j],y[j],z[j],x[k],y[k],z[k])<=4*r*r){
int a1=find(j);
int a2=find(k);
if (a1!=a2) f[a1]=a2;
}
}
}
int s=0;
//看看每一个中是否有洞连接上下面
for (int j=1;j<=tot1;j++){
for (int k=1;k<=tot2;k++){
if (find(f1[j])==find(f2[k])){
s=1;
break;
}
}
if (s==1) break;
}
if (s==1) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}
P3951 小凯的疑惑
#include<bits/stdc++.h>
using namespace std;
long long ans,a,b;
int main()
{
scanf("%lld %lld",&a,&b);
ans=(a-1)*b-a;
printf("%lld",ans);
return 0;
}
P3952 时间复杂度
题面有点长,细节有点小多,但总体难度不应该是蓝题,绿题顶天了
#include<bits/stdc++.h>
using namespace std;
const int N=30;
char s[10];
int T,L,E,F;
int num,cnt,op[N],lx[N];
bool vis[N];
int get(int i)
{
if(s[i]=='n') return -1;
int res=0;
while(s[i]<='9'&&s[i]>='0') res=(res<<1)+(res<<3)+s[i]-'0',i++;
return res;
}
int main()
{
scanf("%d",&T);
while(T--)
{
memset(vis,0,sizeof(vis));
F=1;
E=num=cnt=op[0]=0;
scanf("%d %s",&L,&s);
//O(
if(s[2]!='1') E=get(4);
//O(n^
while(L--)
{
scanf("%s",&s);
if(F!=1)
{
if(s[0]=='F') scanf("%s",&s),scanf("%s",&s),scanf("%s",&s);
continue;
}
if(s[0]=='E')
{
if(!op[0]) F=2;
else
{
if(lx[op[0]]==1) cnt--;
vis[op[op[0]--]]=0;
}
}
else
{
scanf("%s",&s);
op[++op[0]]=s[0]-'a';
scanf("%s",&s);int val1=get(0);
scanf("%s",&s);int val2=get(0);
if(vis[op[op[0]]]) {F=2;continue;}
vis[op[op[0]]]=1;
if(lx[op[0]-1]!=-1)
{
if((val1==-1&&val2!=-1)||(val1!=-1&&val2!=-1&&val1>val2)) lx[op[0]]=-1;
else if(val1!=-1&&val2==-1) lx[op[0]]=1,num=max(num,++cnt);
else lx[op[0]]=0;
}
else lx[op[0]]=-1;
}
}
if(op[0]) F=2;
if(F==1&&num!=E) F=0;
if(F==0) printf("No\n");
else if(F==1) printf("Yes\n");
else printf("ERR\n");
}
}
P3959 宝藏
#include<bits/stdc++.h>
using namespace std;
const int N=12,M=2e3+5,P=1<<12;
int n,m,ans;
int val[P][N],d[N][N],dp[P][N];
bool vis[N];
vector<int>q[P];
void expand(int x)
{
int S=x;
for(int i=0;i<n;++i) vis[i]=(x>>i)&1;
for(int i=0;i<n;++i)
if(vis[i])
{
for(int j=0;j<n;++j)
if(!vis[j]&&d[i][j]!=-1)
{
if(val[x][j]==-1) S|=(1<<j),val[x][j]=d[i][j];
else val[x][j]=min(val[x][j],d[i][j]);
}
}
for(int i=x+1;i<=S;++i)
if((S&i)==i&&(i&x)==x) q[x].push_back(i);
}
int main()
{
scanf("%d %d",&n,&m);
memset(d,-1,sizeof(d));
memset(val,-1,sizeof(val));
for(int i=1,a,b,c;i<=m;++i)
{
scanf("%d %d %d",&a,&b,&c);
a--;b--;
if(d[a][b]==-1) d[a][b]=d[b][a]=c;
else d[a][b]=d[b][a]=min(d[a][b],c);
}
int S=1<<n;
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<S;++i) expand(i);
for(int i=0;i<n;++i) dp[1<<i][0]=0;
for(int t=0;t<n-1;++t)
for(int x=1;x<S;++x)
if(dp[x][t]!=dp[0][0])
{
for(int i=0;i<q[x].size();++i)
{
int zt=x^q[x][i],sum=0;
for(int j=0;j<n;++j)
if((zt>>j)&1) sum+=val[x][j];
dp[q[x][i]][t+1]=min(dp[q[x][i]][t+1],dp[x][t]+sum*(t+1));
}
}
ans=dp[0][0];
for(int t=0;t<n;++t) ans=min(ans,dp[S-1][t]);
printf("%d",ans);
}
P3953 逛公园
/*
如果从一个节点走了一圈回到这个节点,
多出来的L没变,
则说明
这个环上所有边都在最短路上
但只要这个环上有权值>0的边,都会使
dis[u]变大,dis[u]就不是最短路
所以这个环一定是0环
*/
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll t,d[100001],f[100001][51],n,m,k,p;
bool working[100001][51];
struct node{
ll to,edge;
//to表示下一个点
//edge表示长度
};
vector<node> head[100001],h[100001];
//head存正向边
//h存反向边
ll dfs(ll x,ll l)
{
ll ans=0;
if(l<0||l>k) return 0;//超出范围还没走到就返回
if(working[x][l])
{//找到0环
working[x][l]=false;
return -1;
}
if(f[x][l]!=-1) return f[x][l];//这个点已经走过了
working[x][l]=true;
for(ll i=0; i<h[x].size(); i++)
{
ll y=h[x][i].to,z=h[x][i].edge,val=dfs(y,d[x]+l-d[y]-z);
//y表示下一个格子
//z表示剩下的距离
if(val==-1)
{//找到0环
working[x][l]=false;
return -1;
}
ans=(ans+val)%p;
}
working[x][l]=false;//去过了
if(x==1&&l==0) ans++;
/*整张图的初始状态是起点为1,额外开销为0,所有走到初始状态就说明路径合法了,算一种解法*/
f[x][l]=ans;//存下结果
return ans;
}
inline void spfa()
{//最短路,不讲了
memset(d,0x3f,sizeof(d));
memset(f,-1,sizeof(f));
queue<ll> q;
q.push(1);
d[1]=0;
while(!q.empty()){
ll x=q.front(); q.pop();
for(ll i=0; i<head[x].size(); i++){
ll y=head[x][i].to,z=head[x][i].edge;
if(d[y]>d[x]+z){
d[y]=d[x]+z;
q.push(y);
}
}
}
}
ll work()
{
scanf("%lld%lld%lld%lld",&n,&m,&k,&p);
for(ll i=1; i<=n; i++){head[i].clear(); h[i].clear();}
while(m--)
{
ll x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
head[x].push_back(node{y,z});//存正边
h[y].push_back(node{x,z});//存反边
}
spfa();
ll ans=0;
for(ll i=0; i<=k; i++)
{
ll val=dfs(n,i);//调用
if(val==-1) return -1;//找到0环直接退出
ans=(ans+val)%p;//结果增加
}
return ans;
}
int main(){
scanf("%lld",&t);
while(t--) printf("%lld\n",work());
return 0;
}
2018
P1969 积木大赛
#include<bits/stdc++.h>
using namespace std;
int ans,n,a,k;
int main()
{
scanf("%d",&n);
while(n--)
{
scanf("%d",&a);
if(a>k) ans+=(a-k);
k=a;
}
printf("%d",ans);
}
P5019 铺设道路
#include<bits/stdc++.h>
using namespace std;
int n,ans,last,a;
int main()
{
scanf("%d",&n);
while(n--)
{
scanf("%d",&a);
if(a>last) ans=ans+a-last;
last=a;
}
printf("%d",ans);
}
P5020 货币系统
#include<bits/stdc++.h>
using namespace std;
int t,n,a[110],ans;
bool f[25005];
int main()
{
scanf("%d",&t);
while(t--)
{
memset(f,false,sizeof(f));
scanf("%d",&n);
ans=n;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
f[0]=1;
for(int i=1;i<=n;i++)
{
if(f[a[i]])
{
ans--;
continue;
}
for(int j=a[i];j<=a[n];j++)
f[j]=f[j]||f[j-a[i]];
}
printf("%d\n",ans);
}
return 0;
}
2019
P5690 [CSP-SJX2019]日期
#include<bits/stdc++.h>
using namespace std;
int n,m;
int main()
{
scanf("%d-%d",&n,&m);
printf("%d",(n>12||n==0)+(m>31||m==0||(n==2&&m>28)));
}
P5657 格雷码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
void dfs(int x,int y)
{
if(!x) return;
printf("%d",y>=x);
if(y<x) dfs(x/2,y);
else dfs(x/2,x-y-1+x);
}
signed main()
{
scanf("%lld %lld",&n,&m);
dfs(pow(2,n-1),m);
}
P5686 [CSP-SJX2019]和积和
\(∑(1<=l<=n)∑(l<=r<=n)∑(l<=i<=r)a[i]*∑(l<=j<=r)b[j]\)
那么每个\(a[i]*b[j]\)都会算\(min(i,j)*(n-max(i,j)+1)\)次
对于\(i<=j\),\(i*(n-j+1)*a[i]*b[j]-->i*a[i]*(n-j+1)*b[j]\)。
对于\(i>j\),\(j*(n-i+1)*a[i]*b[j]-->(n-i+1)*a[i]*j*b[j]\)。
左右统计\(i*a[i]\)和\((n-i+1)*a[i]\)。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e5+5;
int a[N],b[N],l[N],r[N];
int n,m,mod=1e9+7,ans;
signed main()
{
scanf("%lld",&n);
for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
for(int i=1;i<=n;++i) scanf("%lld",&b[i]);
for(int i=1;i<=n;++i) l[i]=(l[i-1]+i*a[i])%mod;
for(int i=n;i;--i) r[i]=(r[i+1]+(n-i+1)*a[i])%mod;
for(int i=1;i<=n;++i) ans=(ans+b[i]*(((n-i+1)*l[i]+i*r[i+1])%mod))%mod;
printf("%lld",ans);
}
P5658 括号树
不同的子串定义:S中l,r不同的串。
那么每次加入一个括号,跟没加括号之前的比,多出来的字串只有r在现在加入的这个括号这里的。
() () () (())这样是有四组括号,加入最后的那个括号的时候可以搞出来四个不同的字串。
那么每次就记录这个位置向前第一个没有匹配上的(的位置。
捏妈,编不动了,只是直觉这么优化而已,我也不知道为什么可以。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e5+5;
char s[N];
int n,ans,fa[N],pos[N],num[N];
int te,v[N],pre[N],tail[N];
bool pd[N];
inline void add(int x,int y)
{
++te;v[te]=y;pre[te]=tail[x];tail[x]=te;
}
void dfs(int x,int cnt)
{
int p=x,num=0;
while(p&&num>=0)
{
if(s[p]==')') num++;
else if(!--num) cnt++;
p=fa[p];
}
ans=ans^(x*cnt);
for(int i=tail[x];i;i=pre[i]) dfs(v[i],cnt);
}
void dfs2(int x,int cnt)
{
if(s[x]=='(') pos[x]=x;
else if(pos[fa[x]])
{
pos[x]=pos[fa[x]];
num[x]=1;
int p=fa[pos[fa[x]]];
while(pos[p]!=p)
{
num[x]+=num[p];
p=pos[p];
}
pos[x]=p;
}
cnt+=num[x];
ans=ans^(x*cnt);
for(int i=tail[x];i;i=pre[i]) dfs2(v[i],cnt);
}
signed main()
{
scanf("%lld",&n);
scanf("%s",s+1);
for(int i=2;i<=n;++i) scanf("%lld",&fa[i]),add(fa[i],i);
dfs2(1,0);
printf("%lld",ans);
}
P5664 Emiya 家今天的饭
对\(64pts\)的数据,\(n<=40,m<=3\)
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=45,M=2005,mod=998244353;
int n,m,ans;
int a[N][M],dp[N][N][N][N];
inline void add(int &x,int y)
{
x+=y;
if(x>mod) x-=mod;
}
signed main()
{
scanf("%lld %lld",&n,&m);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%lld",&a[i][j]);
if(m==2)
{
dp[0][0][0][0]=1;
for(int i=0;i<n;++i)
for(int j=0;j<=n;++j)
for(int k=0;k<=n;++k)
if(dp[i][j][k][0])
{
add(dp[i+1][j][k][0],dp[i][j][k][0]);
if(j<n&&a[i+1][1]) add(dp[i+1][j+1][k][0],dp[i][j][k][0]*a[i+1][1]%mod);
if(k<n&&a[i+1][2]) add(dp[i+1][j][k+1][0],dp[i][j][k][0]*a[i+1][2]%mod);
}
for(int j=1;j<=n;++j) add(ans,dp[n][j][j][0]);
printf("%lld",ans);
}
else if(m==3)
{
dp[0][0][0][0]=1;
for(int i=0;i<n;++i)
for(int j=0;j<=n;++j)
for(int k=0;k<=n;++k)
for(int s=0;s<=n;++s)
if(dp[i][j][k][s])
{
add(dp[i+1][j][k][s],dp[i][j][k][s]);
if(j<n&&a[i+1][1]) add(dp[i+1][j+1][k][s],dp[i][j][k][s]*a[i+1][1]%mod);
if(k<n&&a[i+1][2]) add(dp[i+1][j][k+1][s],dp[i][j][k][s]*a[i+1][2]%mod);
if(s<n&&a[i+1][3]) add(dp[i+1][j][k][s+1],dp[i][j][k][s]*a[i+1][3]%mod);
}
for(int j=0;j<=n;++j)
for(int k=0;k<=n;++k)
for(int s=0;s<=n;++s)
{
int x=(j+k+s)/2;
if(x==0||j>x||k>x||s>x) continue;
add(ans,dp[n][j][k][s]);
}
printf("%lld",ans);
}
}
84pts:暴力DP:枚举选\(k\)个菜的时候的总方案数,减去不合法方案数。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=105,M=2005,mod=998244353;
int n,m,a[N][M],f[N],dp[M][N][N];
signed main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%d",&a[i][j]),a[i][0]=(a[i][0]+a[i][j])%mod;
f[0]=1;
for(int i=1;i<=n;++i)
for(int j=i;j;--j)
f[j]=(f[j]+f[j-1]*a[i][0])%mod;
for(int i=1;i<=m;++i) dp[i][0][0]=1;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
for(int k=i;k;--k)
{
for(int s=k;s;--s)
dp[j][k][s]=(dp[j][k][s]+dp[j][k-1][s-1]*a[i][j]%mod+dp[j][k-1][s]*(a[i][0]-a[i][j]+mod)%mod)%mod;
dp[j][k][0]=(dp[j][k][0]+dp[j][k-1][0]*(a[i][0]-a[i][j]+mod)%mod)%mod;
}
}
int ans=0,sum=0;
for(int i=1;i<=n;++i)
{
sum=0;
for(int j=i/2+1;j<=i;++j)
for(int k=1;k<=m;++k)
sum=(sum+dp[k][i][j])%mod;
ans=(ans+f[i]-sum+mod)%mod;
}
printf("%lld",ans);
}
不想写了,再写就吐了。

浙公网安备 33010602011771号