@suixinhita
2017-10-25T08:38:24.000000Z
字数 3860
阅读 1022
t1写挂,t2过了,t3挂了...代码细节是绝对需要注意的啊qwq

首先,我们定义dp状态:
那么由上面可得方程如下:
注意第一个的初始化不能为 或 ,最后一个的状态不能为 或
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define ll long longusing namespace std;const int N=1e6+5;const int Q=1e9+7;char s[N];ll cnt[5][N],ans;//0 -->0 1-->front(1) 2--> 2 3-->back(1) 4-->mineint n;void solve(){if(s[1]=='?') cnt[0][2]=cnt[3][3]=cnt[4][4]=1;else if(s[1]=='0') cnt[0][5]=1;else if(s[1]=='1') cnt[3][6]=1;else if(s[1]=='*') cnt[4][7]=1;for(int i=2;i<=n;++i){if(s[i]=='?'){cnt[0][i]=(cnt[0][i-1]+cnt[1][i-1])%Q;if(i!=n) cnt[3][i]=(cnt[0][i-1]+cnt[1][i-1])%Q;cnt[1][i]=cnt[4][i-1];if(i!=n) cnt[2][i]=cnt[4][i-1];cnt[4][i]=((cnt[3][i-1]+cnt[2][i-1])%Q+cnt[4][i-1])%Q;}else{if(s[i]=='0') cnt[0][i]=(cnt[0][i-1]+cnt[1][i-1])%Q;else if(s[i]=='1'){cnt[1][i]=cnt[4][i-1];cnt[3][i]=(cnt[0][i-1]+cnt[1][i-1])%Q;}else if(s[i]=='2') cnt[2][i]=cnt[4][i-1];else if(s[i]=='*') cnt[4][i]=((cnt[3][i-1]+cnt[2][i-1])%Q+cnt[4][i-1])%Q;}}for(int i=0;i<5;++i)if(i!=3) ans=(ans+cnt[i][n])%Q;}int main(){// freopen("mine.in","r",stdin);// freopen("mine.out","w",stdout);scanf("%s",s+1);n=strlen(s+1);solve();cout<<ans;return 0;}

之前做过的题,然后可以有多种做法,我写的是最短路。
可以很容易证明,对于一个点来说,该点的水的高度取决于四周的水(或者地)的高度(同一个方向水和地取最大)的最小值。
那么很容易直接最短路过去。
注意在更新某个节点的时候,我们更新出来的是当前点的水值和高度值之间的最大值。
#include<queue>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define ll long longusing namespace std;const int N=305;const int M=372100;const ll inf=0x3f3f3f3f3f;struct data{int x,y;}dot[M];int m,n;ll dis[N][N];int fx[5]={0,0,0,1,-1};int fy[5]={0,1,-1,0,0};bool ind[N][N];int map[N][N];void bfs(int x){queue<data> q;data k;k.x=k.y=1;q.push(k);while(!q.empty()){data k=q.front();q.pop();dis[k.x][k.y]=max(dis[k.x][k.y],map[k.x][k.y]);for(int k=1;k<=4;++k){int x=k.x+fx[k],y=k.y+fy[k];if(x<1||x>n) continue;if(y<1||y>m) continue;if(dis[x][y]>dis[k.x][k.y]){dis[x][y]=dis[k.x][k.y];if(!ind[x][y]){ind[x][y]=1;data f;f.x=x,f.y=y;q.push(f);}}}ind[k.x][k.y]=0;}}inline int read(){int x=0,y=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-') y=-1;c=getchar();}while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();return x*y;}void init(){for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)map[i][j]=read();for(int i=1;i<=n;++i)dis[i][1]=max(map[i][1],0),dis[i][m]=max(map[i][m],0);for(int j=1;j<=m;++j)dis[1][j]=max(map[i][j],0),dis[1][j]=max(map[n][j],0);for(int i=2;i<n;++i)for(int j=2;j<m;++j) dis[i][j]=inf;}int main(){freopen("water.in","r",stdin);freopen("water.out","w",stdout);n=read(),m=read();init();spfa();for(int i=1;i<=n;++i){for(int j=1;j<=m;++j){ll ans=(dis[i][j]-(ll)map[i][j]);printf("%lld ",ans<0? 0:ans);}puts("");}return 0;}

...暴力没过一个点...心累。
首先,我们知道,这题对于 肯定要分解质因数。
然后我们再想,怎么统计集合里面和这个数互质的数???
互质的不好算,我们想想看,用补集转化一下,不就是和 有相同质因子的个数嘛?
这个好像还可做一些...
所以我们可以统计每个值的倍数个数,然后容斥原理计算答案...
#include<queue>#include<cstdio>#include<algorithm>using namespace std;const int N=2e6+5;const int M=5e5+5;int cnt[500005];long long ans;int piece[M][40],sum[M];int a[N],m,n,x;bool in[N];bool vis[M];void pre_tab(){for(int i=2;i<M;++i){if(vis[i]) continue;for(int j=1;i*j<M;++j){int f=i*j;vis[f]=1;piece[f][++sum[f]]=i;}}}void dfs(int now,int num,int nowit,int ty){if(now>sum[x]){if(ty==-1)cnt[num]--;ans+=nowit*cnt[num];if(ty==1)cnt[num]++;return ;}dfs(now+1,num,nowit,ty);dfs(now+1,num*piece[x][now],-nowit,ty);}inline int read(){int x=0;char c=getchar();while(c<'0'||c>'9') c=getchar();while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();return x;}int main(){// freopen("gcd.in","r",stdin);// freopen("gcd.out","w",stdout);pre_tab();n=read(),m=read();for(int i=1;i<=n;++i) a[i]=read();//broken(i);for(int i=1;i<=m;++i){x=read();if(!in[x]){in[x]=1;x=a[x];dfs(1,1,1,1);}else{in[x]=0;x=a[x];dfs(1,1,-1,-1);}printf("%lld\n",ans);}return 0;}