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 转圈游戏

image-20200911154019495

#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 火柴排队

image-20200911153956213

image-20200911154004234

#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 生活大爆炸版石头剪刀布

image-20200911154151815

image-20200911154210742

#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.秦九韶算法:

image-20200911171158797

掌握以上两点本题就可以切掉了。

\(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);
}

不想写了,再写就吐了。

posted @ 2020-10-24 14:21  林生。  阅读(158)  评论(0)    收藏  举报