题解:
这题太水辣
注意开 long long
但我不是没开long long 的锅
我是
输出 long long 要用 lld 啊
大梦身先醒,80可海星
PS:百度了一下 long (ld) 和 int(d) 的区别,以前有大区别,现在没了
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<queue>
#include<cstdlib>
using namespace std;
#define ll long long
inline ll read()
{
ll ans=0;
char last=' ',ch=getchar();
while(ch<'0'||ch>'9') last=ch,ch=getchar();
while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
if(last=='-') ans=-ans;
return ans;
}
ll a,b;
ll x,y,z;
ll gcd(ll aa,ll bb)
{
if(bb==0) return aa;
return gcd(bb,aa%bb);
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
a=read();b=read();
x=gcd(a,b);
y=a*b/x;
z=x^y;
printf("%lld\n",z); //long long是lld
return 0;
}
题解
提供一种暴力解法,就是60%的数据N<=1000,所以想到可以Floyd暴力处理
Floyd如果两点之间有路径,那么就可以记录一下这条路径上的最大点和最小点啊
然后for循环,如果两点之间有路径,那就求出最大差值辣
//正着倒着跑BFS
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<queue>
#include<cstdlib>
using namespace std;
inline int read()
{
int ans=0;
char last=' ',ch=getchar();
while(ch<'0'||ch>'9') last=ch,ch=getchar();
while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
if(last=='-') ans=-ans;
return ans;
}
const int maxn=1e5+10,maxm=500005;
int n,m,ans=0;
int w[maxn];
int zuida=0,zuixiao=1e6;
struct node
{
int val;
int maxx=0;
int minn=1e6;
}dis[4001][4001];
int main()
{
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
n=read();m=read();
for(int i=1;i<=n;i++)
{
w[i]=read();
zuida=max(zuida,w[i]);
zuixiao=min(zuixiao,w[i]);
}
if(n<=4000)
{
for(int i=1;i<=m;i++)
{
int u,v;
u=read();v=read();
dis[u][v].val =1;
dis[u][v].maxx =max(w[u],w[v]);
dis[u][v].minn =min(w[u],w[v]);
ans=max(ans,dis[u][v].maxx -dis[u][v].minn );
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(dis[i][k].val &&dis[k][j].val )
{
if(dis[i][k].val +dis[k][j].val>dis[i][j].val )
{
dis[i][j].val =max(dis[i][j].val ,dis[i][k].val +dis[k][j].val );
dis[i][j].maxx =max(dis[i][j].maxx,max(w[i],max(w[j],w[k])));
dis[i][j].minn =min(dis[i][j].minn,min(w[i],min(w[j],w[k])));
}
ans=max(ans,dis[i][j].maxx -dis[i][j].minn );
}
printf("%d\n",ans);
}
else
printf("%d\n",zuida-zuixiao);
return 0;
}
Floyd暴力代码
下面正解
DFS从一个点出发,能到达的最小的点
然后反向DFS,向回走能走的最小值
枚举每个点作为起点和和终点
我们可以枚举max是哪个点,假设当前点事是最大点max
那么它的路径走到了一个最小点min,所以后面所有经过min的路径都会把最小值更成min ,除非还有更小的值,这在后面会被覆盖掉
但是这样好慢啊
优化DFS
每个点都要前后BFS一下
BFS顺序不影响
所有点权从小到大,一个一个BFS
每个点标记一下,它向前走的最小点是多少
每个点一旦被BFS到,它向前走的最小点已经被更新完了
两遍BFS是因为min->max 或者 max->min
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=100010;
const int maxm=500010;
int n,m,en,result[maxn],z[maxn],y[maxn];
struct edge
{
int s,e;
bool rev;
edge *next;
}*v[maxn],ed[maxm<<1];
void add_edge(int s,int e)
{
en++;
ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;v[s]->rev=false;
en++;
ed[en].next=v[e];v[e]=ed+en;v[e]->e=s;v[s]->rev=true;
}
bool cmp(int a,int b)
{
return z[a]<z[b];
}
void bfs(int p)
{
queue<int> q;
if (!result[p]) result[p]=z[p];
q.push(p);
while (q.size())
{
int now=q.front();
q.pop();
for (edge *e=v[now];e;e=e->next)
if (!e->rev && !result[e->e])
{
result[e->e]=z[p];
q.push(e->e);
}
}
q.push(p);
while (q.size())
{
int now=q.front();
q.pop();
for (edge *e=v[now];e;e=e->next)
if (e->rev && !result[e->e])
{
result[e->e]=z[p];
q.push(e->e);
}
}
}
int main()
{
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
scanf("%d%d",&n,&m);
for (int a=1;a<=n;a++)
scanf("%d",&z[a]);
for (int a=1;a<=m;a++)
{
int s,e;
scanf("%d%d",&s,&e);
add_edge(s,e);
}
for (int a=1;a<=n;a++)
y[a]=a;
sort(y+1,y+n+1,cmp);
for (int a=1;a<=n;a++)
bfs(y[a]);
int ans=0;
for (int a=1;a<=n;a++)
ans=max(ans,z[a]-result[a]);
printf("%d\n",ans);
return 0;
}
题解
首先DFS暴力来一波 40'
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<queue>
#include<cstdlib>
using namespace std;
inline int read()
{
int ans=0;
char last=' ',ch=getchar();
while(ch<'0'||ch>'9') last=ch,ch=getchar();
while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
if(last=='-') ans=-ans;
return ans;
}
int n,c,ans=1e7+10;
int shu[20],cnt_num=0;
bool vis[20][20],need[20],flag=0;
struct node
{
int num,lef,rig;
}a[20];
void dfs(int now,int step,int ready)
{
if(ready>=cnt_num)
{
flag=1;
ans=min(ans,step);
return;
}
int kk=shu[now];
if(!need[kk]) return;
int a1=a[kk].lef ,a2=a[kk].rig ;
for(int i=1;i<=n;i++)
{
if(i==kk) continue;
if(vis[i][kk]||vis[kk][i]) continue;
int b1=a[i].lef ,b2=a[i].rig ;
if(abs(a1-b1)<=c)
{
vis[i][kk]=vis[kk][i]=1;
a[kk].rig =b1;
a[i].lef=a2;
need[kk]=0;
if(need[i]&&abs(a2-b2)<=c)
{
need[i]=0;
dfs(now+1,step+1,ready+2);
need[i]=1;
}
else
{
if(!need[i]&&abs(a2-b2)>c)
{
shu[++cnt_num]=i;
need[i]=1;
dfs(now+1,step+1,ready+1);
need[i]=0;
shu[--cnt_num]=0;
}
else
dfs(now+1,step+1,ready+1);
}
need[kk]=1;
a[kk].rig =a2;
a[i].lef=b1;
vis[i][kk]=vis[kk][i]=0;
}
if(abs(a1-b2)<=c)
{
vis[i][kk]=vis[kk][i]=1;
a[kk].rig =b2;
a[i].rig=a2;
need[kk]=0;
if(need[i]&&abs(a2-b1)<=c)
{
need[i]=0;
dfs(now+1,step+1,ready+2);
need[i]=1;
}
else
{
if(!need[i]&&abs(a2-b1)>c)
{
shu[++cnt_num]=i;
need[i]=1;
dfs(now+1,step+1,ready+1);
need[i]=0;
shu[--cnt_num]=0;
}
else
dfs(now+1,step+1,ready+1);
}
need[kk]=1;
a[kk].rig =a2;
a[i].rig=b2;
vis[i][kk]=vis[kk][i]=0;
}
}
}
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
n=read();c=read();
for(int i=1;i<=n;i++)
{
a[i].lef =read();
a[i].rig =read();
if(abs(a[i].lef -a[i].rig)>c )
{
shu[++cnt_num]=i;
need[i]=1;
}
}
if(cnt_num==0)
{
printf("0\n");
return 0;
}
dfs(1,0,0);
if(flag) printf("%d",ans);
else printf("-1");
return 0;
}
DFS 暴力
看到数据 n<=16 首先想到状压DP
f[s] s对应的四个人能不能通过交换变合法
只需要把2n个数排个序
最后只需要判断相邻的两把刷子能不能实现c合法
问题转化为N个人最少需要交换多少次刷子才合法
现在答案最大是多少(也就是最坏情况)??
N个人总能通过n-1次交换才会合法(最坏情况)
对于当前一个人,比如1号
分类讨论:
1.手里拿着 C1 C2 ,那么他就不需要交换了,0次操作
2.一个手里拿 C1 ,另一个手里 是一个奇奇怪怪的刷子 ? ,我们只需要把 C2换回来就好啦,1次操作
F[s] s这一堆人能不能通过内部交换实现合法(bool)
G[s] s这一堆人合法的最小交换次数,ans<=k-1 如果内部可以自己解决,初始化k-1,目标找一个比k-1还小的数
枚举S的子集 s’ 另一部分 s^s’
每次多分一个部分,ans就少1
问题就转化成最多把n个人分成多少部分,他们内部可以自己解决刷子分配
f[s] 记录可不可能
g[s] 记录最多分成多少部分
G[s]=max( g[s] , g[s’]+g[s^s’]
Ans=n-g[2^n -1]
代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=20;
int n,d,z[maxn][2],y[maxn<<1],f[1<<maxn];
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
scanf("%d%d",&n,&d);
for (int a=1;a<=n;a++)
scanf("%d%d",&z[a][0],&z[a][1]);
for (int a=0;a<(1<<n);a++)
{
int cnt=0;
for (int b=1;b<=n;b++)
if (a&(1<<(b-1)))
{
y[++cnt]=z[b][0];
y[++cnt]=z[b][1];
}
sort(y+1,y+cnt+1);
bool able=true;
for (int b=1;b<=cnt;b+=2)
if (y[b+1]-y[b]>d) able=false;
if (able) f[a]=1;
else f[a]=-0x3f3f3f3f;
}
f[0]=0;
for (int a=1;a<(1<<n);a++)
for (int b=a;b;b=(b-1)&a)
f[a]=max(f[a],f[a^b]+f[b]);
if (f[(1<<n)-1]<0) printf("-1\n");
else printf("%d\n",n-f[(1<<n)-1]);
return 0;
}
题解
不好意思破队形了,暴力没写完然后一着急写错了然后还查不出错来,样例都没过
区间加上feibo,区间求和
C相当于
性质1:两个斐波那契数列
只需要记录给一个序列加的第1个第2个数字
和怎么变???
所有的c都可以用c1 c2 表示出来
预处理数组,代表当前的是加几个c1 几个c2
求前缀和,也是
对一个长度为L的区间,第一个数字加上c1,第二个数字加上c2
代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
using namespace std;
const int BUF_SIZE = 30;
char buf[BUF_SIZE], *buf_s = buf, *buf_t = buf + 1;
#define PTR_NEXT() \
{ \
buf_s ++; \
if (buf_s == buf_t) \
{ \
buf_s = buf; \
buf_t = buf + fread(buf, 1, BUF_SIZE, stdin); \
} \
}
#define readint(_n_) \
{ \
while (*buf_s != '-' && !isdigit(*buf_s)) \
PTR_NEXT(); \
bool register _nega_ = false; \
if (*buf_s == '-') \
{ \
_nega_ = true; \
PTR_NEXT(); \
} \
int register _x_ = 0; \
while (isdigit(*buf_s)) \
{ \
_x_ = _x_ * 10 + *buf_s - '0'; \
PTR_NEXT(); \
} \
if (_nega_) \
_x_ = -_x_; \
(_n_) = (_x_); \
}
#define wmt 1,n,1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=100010;
const int mo=1000000007;
int n,m,z[maxn<<2|1],col[maxn<<2|1][2];
struct rec
{
int a,b;
rec(){}
rec(int a_,int b_){
a=a_;if (a>=mo) a-=mo;
b=b_;if (b>=mo) b-=mo;
}
}f[maxn],sum[maxn];
rec operator+(const rec &a,const rec &b)
{
return rec(a.a+b.a,a.b+b.b);
}
int operator*(const rec &a,const rec &b)
{
return (1ll*a.a*b.a+1ll*a.b*b.b)%mo;
}
void update(int rt)
{
z[rt]=z[rt<<1]+z[rt<<1|1];
if (z[rt]>=mo) z[rt]-=mo;
}
void color(int l,int r,int rt,int a,int b)
{
col[rt][0]+=a;if (col[rt][0]>=mo) col[rt][0]-=mo;
col[rt][1]+=b;if (col[rt][1]>=mo) col[rt][1]-=mo;
z[rt]+= rec(a,b)*sum[r-l];if (z[rt]>=mo) z[rt]-=mo;
}
void push_col(int l,int r,int rt)
{
if (col[rt][0] || col[rt][1])
{
int m=(l+r)>>1;
color(l,m,rt<<1,col[rt][0],col[rt][1]);
int a=rec(col[rt][0],col[rt][1])*f[m+1-l];
int b=rec(col[rt][0],col[rt][1])*f[m+2-l];
color(m+1,r,rt<<1|1,a,b);
col[rt][0]=0;
col[rt][1]=0;
}
}
void build(int l,int r,int rt)
{
if (l==r)
{
readint(z[rt]);
return;
}
int m=(l+r)>>1;
build(lson);
build(rson);
update(rt);
}
void modify(int l,int r,int rt,int nowl,int nowr,int a,int b)
{
if (nowl<=l && r<=nowr)
{
int a_=rec(a,b)*f[l-nowl];
int b_=rec(a,b)*f[l+1-nowl];
color(l,r,rt,a_,b_);
return;
}
push_col(l,r,rt);
int m=(l+r)>>1;
if (nowl<=m) modify(lson,nowl,nowr,a,b);
if (m<nowr) modify(rson,nowl,nowr,a,b);
update(rt);
}
int query(int l,int r,int rt,int nowl,int nowr)
{
if (nowl<=l && r<=nowr) return z[rt];
push_col(l,r,rt);
int m=(l+r)>>1;
int ans=0;
if (nowl<=m) ans=query(lson,nowl,nowr);
if (m<nowr) ans+=query(rson,nowl,nowr);
if (ans>=mo) ans-=mo;
return ans;
}
int main()
{
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
f[0]=rec(1,0);
f[1]=rec(0,1);
for (int a=2;a<maxn;a++)
f[a] = f[a-1]+f[a-2];
sum[0]=f[0];
for (int a=1;a<maxn;a++)
sum[a]=sum[a-1]+f[a];
readint(n);
readint(m);
build(wmt);
for (int a=1;a<=m;a++)
{
int opt,l,r;
readint(opt);
readint(l);
readint(r);
if (opt==1) printf("%d\n",query(wmt,l,r));
else
{
int x;
readint(x);
modify(wmt,l,r,f[x].b,f[x+1].b);
}
}
return 0;
}
rank 2 还不错
一定要快点打代码,暴力T4来不及写啦(主要是线段树忘了+树状数组写错了)