【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吧...
  • 暴力分要拿够!
posted @ 2019-08-13 21:09  委屈的咸鱼鱼鱼鱼  阅读(108)  评论(0编辑  收藏  举报