【2019.8.13】
异或求值
求1到n的异或值,即1^ 2...^n
50%的数据:$n≤10^6 $ 100%的数据:\(1≤n≤10^{18}\)
hei水 看了题先挨个挨个列了出来 然后发现各几个就会出现一个0
后面讲题说,当一个偶数\(+1\)变成奇数时它们异或的值只会是1(其它位都相同只有最后一位不同)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rg register
const int N=1000+5,M=200000+5,inf=0x3f3f3f3f,P=19650827;
ll n,x,ans=0;
template <class t>void rd(t &x){
x=0;int w=0;char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
x=w?-x:x;
}
int main(){
freopen("xor.in","r",stdin);
freopen("xor.out","w",stdout);
rd(n);
if(!(n+1)%4) return puts("0"),0;
x=(n/4)*4;
for(x;x<=n;++x) ans^=x;
printf("%lld",ans);
return 0;
}
染色方案
有一颗N 个节点的树,节点用1, 2.....N编号。你要给它染色,使得相邻节点的颜色不同。有M种颜色,用1,2.....M编号。每个节点可以染M 种颜色中的若干种,求不同染色方案的数量除以(10^9 + 7)的余数。
一道树形dp 最后想不出来了 打暴力还打挂了...
是lsy大佬的思路 考试的时候思路和她是一样的 但考试的时候我脑壳没有转过来弯 并没有想到再来一个数组记录f[u][color]来记录u这个点染成color颜色时的方案数
当时推的时候意识到当前转移和当前点选颜色有关 but.... emmmmm...
ans[u]就等于u这个点选择各种颜色的方案数和
但在l洛谷上会MLE... 可以把col数组和ans数组都压在f数组里qwq
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rg register
const int N=5000+5,M=5000+5,inf=0x3f3f3f3f,P=1e9+7;
int n,m,ans[N],col[N][N],f[N][N];
template <class t>void rd(t &x){
x=0;int w=0;char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
x=w?-x:x;
}
int head[N],tot=0;
struct edge{int v,nxt;}e[N<<1];
void add(int u,int v){
e[++tot]=(edge){v,head[u]},head[u]=tot;
}
void dfs(int u,int fa){
for(int i=head[u],v;i;i=e[i].nxt){
v=e[i].v;
if(v==fa) continue;
dfs(v,u);
for(int j=1;j<=col[u][0];++j)
f[u][col[u][j]]=((ll)f[u][col[u][j]]*(ans[v]-f[v][col[u][j]]+P))%P;
}
for(int i=1;i<=col[u][0];++i) ans[u]=(ans[u]+f[u][col[u][i]])%P;
}
int main(){
freopen("color.in","r",stdin);
freopen("color.out","w",stdout);
rd(n),rd(m);
for(int i=1,k;i<=n;++i){
rd(k),col[i][0]=k;
for(int j=1,x;j<=k;++j) rd(x),col[i][j]=x,f[i][x]=1;
}
for(int i=1,u,v;i<n;++i)
rd(u),rd(v),add(u,v),add(v,u);
dfs(1,0);
printf("%d",ans[1]);
return 0;
}
新三国争霸
PP 特别喜欢玩即时战略类游戏,但他觉得那些游戏都有美中不足的地方。灾害总不降临道路,而只降临城市,而且道路不能被占领,没有保护粮草的真实性。于是他就研发了《新三国争霸》。
在这款游戏中,加入灾害对道路的影响(也就是一旦道路W[i,j]受到了灾害的影响,那么在一定时间内,这条路将不能通过)和道路的占领权(对于一条道路W[i,j],至少需要K[i,j]个士兵才能守住)。
PP可真是高手,不一会,就攻下了N-1座城市,加上原来的就有N座城市了,但他忽略了一点……那就是防守同样重要,不过现在还来的及。因为才打完仗所以很多城市都需要建设,PP估算了一下,大概需要T天。他现在无暇分身进攻了,只好在这T天内好好的搞建设了。所以他要派士兵占领一些道路,以确保任何两个城市之间都有路(不然敌人就要分而攻之了,是很危险的)。士兵可不是白干活的,每个士兵每天都要吃掉V的军粮。因为有灾害,所以方案可能有变化(每改变一次就需要K的军粮,初始方案也需要K的军粮)。
因为游戏是PP编的,所以他知道什么时候有灾害。PP可是一个很节约的人,他希望这T天在道路的防守上花最少的军粮。
对于所有数据:\(N<=300,M<=5000 ,T<=50,P<=8000\)
和[ZJOI2006]物流运输 很像(或者一样?) 因为之前做过物流运输所以这题就按的我做物流运输的方法
枚举时间段 算出各个时间段只走一种方案所需的花费 最后dp转移
我把这段时间只要该路有一天不能走就全封掉(虽然我不知道为什么 但是对答案不影响 因为\(T^2\)枚举了各个时间段)
考试的时候枚举该时间段内封掉的路我用的N^2枚举i能否到j 而N^2就已经到9w了QAQ 后面我看 直接枚举m条边不就好了?! 成功被自己sb到...
标程有一个小技巧(?) 判断这个时间段是否被封可以用前缀和
先在读入时将其读入第k天u到v不能走lim[u][v][k]=1 然后算一遍前缀和 判断u到v在l~r这段时间有没有被锁就判断lim[u][v][l]是否等于lim[u][v][r] (虽然在我的方法里没啥用和我的40分一样... 但是很巧妙就对了)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rg register
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)>(y)?(y):(x))
const int N=300+5,M=5000+5,inf=0x3f3f3f3f,P=19650827;
int n,m,t,vv,k,p,f[N],val[60][60],ans[60][60];
bool lim[N][N][60],can[N][N];
template <class t>void rd(t &x){
x=0;int w=0;char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
x=w?-x:x;
}
int head[N],tot=0;
struct edge{
int u,v,w;
bool operator<(const edge&A)const{return w<A.w;}
}e[M];
int sum,cnt;
int find(int x) {return f[x]==x?x:f[x]=find(f[x]);}
void kruskal(){
for(rg int i=1;i<=n;++i) f[i]=i;
for(rg int i=1,u,v;i<=m;++i){
u=e[i].u,v=e[i].v;
if(cnt>=n-1) return;
if(!can[u][v]&&find(u)!=find(v)){
f[f[u]]=f[v];
sum+=e[i].w,++cnt;
}
}
}
int main(){
freopen("three.in","r",stdin);
freopen("three.out","w",stdout);
rd(n),rd(m),rd(t),rd(vv),rd(k);
for(int i=1,u,v,w;i<=m;++i)
rd(e[i].u),rd(e[i].v),rd(e[i].w);
sort(e+1,e+m+1);
rd(p);
for(int i=1,x,y,l,r;i<=p;++i){
rd(x),rd(y),rd(l),rd(r);
for(int j=l;j<=r;++j) lim[x][y][j]=lim[y][x][j]=1;
}
for(int r=1;r<=t;++r)
for(int l=1;l<=r;++l){
memset(can,0,sizeof(can));
for(int i=1,u,v;i<=m;++i)
for(int k=l;k<=r;++k){
u=e[i].u,v=e[i].v;
if(!can[u][v]&&lim[u][v][k]) can[u][v]=can[v][u]=1;
}
sum=cnt=0,kruskal();
if(cnt<n-1) val[l][r]=inf;
else val[l][r]=sum*(r-l+1)*vv;
}
memset(ans,inf,sizeof(ans));
for(int i=1;i<=t;++i) ans[1][i]=val[1][i];
for(int i=1;i<=t;++i)
for(int j=1;j<i;++j) ans[1][i]=Min(ans[1][i],ans[1][j]+val[j+1][i]+k);
printf("%d",ans[1][t]+k);
return 0;
}
summary
这次感觉难度还行?只是我太弱了
- 遇到类似的题不能盲目自信 还是要冷静分析
- 加强树形dp吧...
- 暴力分要拿够!