20170707测试

Day1

T1寻找羔羊

时间限制: 1 Sec  内存限制: 256 MB

题目描述

给定一个由小写字母组成的字符串,寻找包含“agnus”(羔羊)的子串的个数。注意:当且仅当两个子串的起始位置和终点不同时,这两个子串属于不同的子串。

输入

只有一个字符串,表示题中所述的字符串。

输出

仅一个数字,表示满足题意的子串个数。

样例输入

agnusbgnus

样例输出

6

提示

 

【样例解释】

    6个子串分别是:agnus、agnusb、agnusbg、agnusbgn、agnusbgnu、agnusbgnus。

 

【数据规模和约定】

对于 40%的数据,字符串长度<=1000

对于 100%的数据,字符串长度<=30000

 这道题我们先考虑一下一个agnus对整个串的贡献。

设第一个字母a的位置在第i个,有i*(n-i-3)个字串包含它。

当然这样是有重复的如果一个子串内包含i个字串答案就增加了i-1个,

所以要把所有的agnus和后一个agnus共同有的子串给减掉-(a[i])*(n-a[i+1]-3)。

代码:

 1 #include<iostream> 
 2 #include<algorithm> 
 3 #include<cstdio> 
 4 #include<cstring> 
 5 #include<cmath> 
 6 #include<cstdlib> 
 7 #include<vector> 
 8 using namespace std; 
 9 typedef long long ll; 
10 typedef long double ld; 
11 typedef pair<int,int> pr; 
12 const double pi=acos(-1); 
13 #define rep(i,a,n) for(int i=a;i<=n;i++) 
14 #define per(i,n,a) for(int i=n;i>=a;i--) 
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i]) 
16 #define clr(a) memset(a,0,sizeof(a)) 
17 #define pb push_back 
18 #define mp make_pair 
19 #define fi first 
20 #define sc second 
21 #define pq priority_queue 
22 #define pqb priority_queue <int, vector<int>, less<int> > 
23 #define pqs priority_queue <int, vector<int>, greater<int> > 
24 #define vec vector 
25 ld eps=1e-9; 
26 ll pp=1000000007; 
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;} 
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;} 
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } 
30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; } 
31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1}; 
32 ll read(){ ll ans=0; char last=' ',ch=getchar(); 
33 while(ch<'0' || ch>'9')last=ch,ch=getchar(); 
34 while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar(); 
35 if(last=='-')ans=-ans; return ans; 
36 } 
37 char ch[30005],ag[]="agnus";
38 int a[30005];
39 long long ans;
40 int main(){
41     scanf("%s",ch); int n=strlen(ch),nu=0;
42     for (int i=0;i<n;i++){
43         bool flag=1;
44         for (int j=0;j<5;j++)
45             if (ch[i+j]!=ag[j]) { flag=0; break; }
46         if (flag) a[++nu]=i+1; 
47     }
48     for (int i=1;i<=nu;i++) ans+=(a[i])*(n-a[i]-3);
49     for (int i=1;i<nu;i++) ans-=(a[i])*(n-a[i+1]-3);
50     printf("%lld",ans);
51     return 0;
52 }
View Code

T2统计损失

时间限制: 1 Sec  内存限制: 512 MB

题目描述

SJY有一天被LLT紧急召去计算一些可能的损失。LLT元首管理的SHB国的交通形成了一棵树,现在将会出现一颗陨石砸在SHB国中,并且陨石砸毁的必定是SHB国构成的交通树上的一条路径。SHB国的损失可表示为被砸毁的路径上的所有城市价值之积。现在还暂时无法确定陨石的掉落路线,所以LLT元首希望SJY能够告诉他SHB国在受到每一种砸毁方式后会受到的损失之和模10086之后的值。注意:单独一个节点也被认为是合法的路径。

输入

第1行一个数n,表示城市数。
第2行n个数,第i个数表示第i个城市的价值。
第3到n+1行,每行两个数u,v,表示城市u,v之间有一条道路。

输出

包含一个数,表示SHB国将受到的损失之和。

样例输入

5 7 6 6 1 1 1 2 2 3 2 4 1 5

样例输出

778

提示

 

【数据规模和约定】

n<=100;

n<=3000;

n<=100000
首先我们能不能在线性时间内求出某个点在一条路径上对答案的贡献。

那我们能不能对树这么做能?

但一颗有根树的两棵子树间的路径怎么办?多棵子树?

 

于是我们只要一遍的dfs就能统计出所有点的贡献。

代码:

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<int,int> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 #define vec vector
25 ld eps=1e-9;
26 ll pp=10086;
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
30 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
31 ll read(){ ll ans=0; char last=' ',ch=getchar();
32 while(ch<'0' || ch>'9')last=ch,ch=getchar();
33 while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
34 if(last=='-')ans=-ans; return ans;
35 }
36 #define N 100005
37 int v[N+N],next[N+N],head[N+N],a[N],f[N],e,ans;
38 void add(int x,int y){ v[++e]=y; next[e]=head[x]; head[x]=e;}
39 void dfs(int x,int fa){
40     long long tol=0,tol_=0;
41     for (int i=head[x];i;i=next[i])
42     if (v[i]!=fa){
43         dfs(v[i],x);
44         tol+=f[v[i]];
45         tol_+=f[v[i]]*f[v[i]];
46     }
47     f[x]=mo((tol+1)*a[x],pp);
48     tol=tol*tol;
49     tol=(tol-tol_)*a[x]/2;
50     ans=mo(ans+f[x]+tol,pp);
51 }
52 int main()
53 {
54     int n=read();
55     for (int i=1;i<=n;i++) a[i]=read(),a[i]=mo(a[i],pp);
56     for (int i=1;i<n;i++) {
57         int x=read(),y=read();
58         add(x,y); add(y,x);
59     } 
60     dfs(1,-1);
61     cout<<ans<<endl;
62     return 0;
63  } 
View Code

T3简单题

时间限制: 1 Sec  内存限制: 512 MB

题目描述

    dzy 手上有一张n 个点m 条边的联通无向图,仙人掌是一张每条边最多在一个简单环内的联通无向图。他想求这个无向图的生成仙人掌中最多有多少条边。
    但是dzy 觉得这个问题太简单了,于是他定义了“美丽的生成仙人掌”,即在一个生成仙人掌中如果满足对于任意编号为i,j(i < j) 的两点,存在一条它们之间的简单路径上面有j-i+1 个点,则这个仙人掌是美丽的。
他现在想要知道这张图的美丽的生成仙人掌中最多有多少条边,你能帮帮他吗?

输入

第一行两个整数n,m。接下来m 行每行两个整数ui,vi,表示这两个点之间有一条无向边。保证图中没有自环。

输出

仅一行一个整数表示答案。

样例输入

2 1 1 2

样例输出

1

提示

 

【数据规模和约定】 

    对于10% 的数据,n <=10。

    对于30% 的数据,n <=10^3。

    对于100% 的数据,n <=10^5,m <= 2n。

这道题出第真想骂出题人,什么鬼啊,

研究题目可以发现,美丽的生成仙人掌中i 和i+ 1中必定有一条边。所以问题变成了:我们在一条链上加上若干条边使得得到的图是仙人掌且边数量最大。

显而易见,每一条非链边对应了链上的一个区间。于是问题就变成了选出最多数量的线段使得其互不相交。

不能加一句,一定有解吗?

好解决选出最多数量的线段使得其互不相交这个问题在算法导论第237页第16章16.1中有详细解答。也就是按尾排序贪心。

代码:

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<int,int> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 #define vec vector
25 ld eps=1e-9;
26 ll pp=1000000007;
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; }
31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
32 ll read(){ ll ans=0; char last=' ',ch=getchar();
33 while(ch<'0' || ch>'9')last=ch,ch=getchar();
34 while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
35 if(last=='-')ans=-ans; return ans;
36 }
37 struct node{
38     int x,y;
39 }a[200005];
40 bool cmp(node a,node b){
41     return a.y<b.y;
42 }
43 int f[200005];
44 int main()
45 {
46     int n=read(),m=read(),nu=0;
47     for (int i=1;i<=m;i++){
48         int x=read(),y=read();
49         if (x>y) swap(x,y);
50         if (y-x==1 && !f[x]) f[x]=1;
51         else {
52             a[++nu]=(node){x,y};
53         }
54     }
55     sort(a+1,a+nu+1,cmp); int r=0,ans=n-1;
56     for (int i=1;i<=nu;i++)
57         if (a[i].x>=r){ans++; r=a[i].y;}
58     cout<<ans<<endl;
59     return 0;
60  } 
View Code

Day1总结,T2推错了告诉我们要仔细,T3告诉我们要乱搞。

Day2

T1七天使的通讯

时间限制: 2 Sec  内存限制: 256 MB

题目描述

n个天使排成一条直线,某些天使之间需要互相联系,他们之间的通讯可以通过黑白两种通道中的一种;所有通道必须在直线同侧(另一侧是地面);为了保证通讯效率,同种颜色的所有通道之间不能相交。请计算能否建立这种通讯方案。

输入

    第一行一个数T,表示接下来有T个询问。
    对于每个询问:第一行两个数n,m,分别表示有n个天使、需要建立通讯线路的天使有m对;接下来有m行,每行两个数a、b,表示a、b两个天使需要通讯。

输出

对于每个询问,输出一行“sane”表示有可行方案、“non”表示无解

样例输入

1 7 5 1 3 2 7 3 4 7 4 6 5

样例输出

sane

提示

 

【样例解释】

样例中共有一个询问。




在(1,3)、(4,7)、(5,6)之间连黑色通道,在(2,7)、(3,4)之间连白色通道,每条通道都成功建立,且同种颜色的通道没有相交,所以输出sane。


【数据规模和约定】

对于 20%的数据,1<=n<=50,1<=m<=15

对于 50%的数据,1<=n<=1000,1<=m<=300

对于 100%的数据,1<=n<=5000,1<=m<=1000,1<=T<=10,1<=a<=n,1<=b<=n

数据保证每对(a,b)不重复,且a不等于b

【提示】

当两条线路有一对相同的端点时,这两条线路不相交。

也就是说,对于线路(a,b)和线路(c,d)(a<b且c<d),当且仅当a<c<b<d或者c<a<d<b时这两条线路相交。 

对于这题我们有很多方法:并查集,贪心,二分图。

二分图的详解:

将每个通道设为一个节点,先暴力判断每两条通道如果是同种颜色会不会相交,

如果会相交就在这两个节点之间连无向边,说明它们不能为同种颜色(必须在二分图两边)。

然后对组成的无向图进行二分图判定(DFS染色),如果染色成功说明该图是一个二分图,即有解,否则无解。

这里给出贪心代码:

 1 #include<iostream> 
 2 #include<algorithm> 
 3 #include<cstdio> 
 4 #include<cstring> 
 5 #include<cmath> 
 6 #include<cstdlib> 
 7 #include<vector> 
 8 using namespace std; 
 9 typedef long long ll; 
10 typedef long double ld; 
11 typedef pair<int,int> pr; 
12 const double pi=acos(-1); 
13 #define rep(i,a,n) for(int i=a;i<=n;i++) 
14 #define per(i,n,a) for(int i=n;i>=a;i--) 
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i]) 
16 #define clr(a) memset(a,0,sizeof(a)) 
17 #define pb push_back 
18 #define mp make_pair 
19 #define fi first 
20 #define sc second 
21 #define pq priority_queue 
22 #define pqb priority_queue <int, vector<int>, less<int> > 
23 #define pqs priority_queue <int, vector<int>, greater<int> > 
24 #define vec vector 
25 ld eps=1e-9; 
26 ll pp=1000000007; 
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;} 
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;} 
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } 
30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; } 
31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1}; 
32 ll read(){ ll ans=0; char last=' ',ch=getchar(); 
33 while(ch<'0' || ch>'9')last=ch,ch=getchar(); 
34 while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar(); 
35 if(last=='-')ans=-ans; return ans; 
36 } 
37 const int inf=1e08;
38 int f[5005],b[5005],w[5005];
39 int main(){
40     int T=read();
41     while (T--){
42         int n=read(),m=read(),flag=1;
43         for (int i=1;i<=n;i++) f[i]=0;
44         for (int i=1;i<=m;i++){
45             int x=read(),y=read();
46             if (y<x) swap(x,y);
47             f[x]=max(f[x],y);
48         }
49         for (int i=1;i<=n;i++) b[i]=inf,w[i]=inf;
50         for (int i=1;i<=n;i++)
51         if (f[i]){
52             if (b[i]<f[i] && w[i]<f[i]){
53                 flag=0; break;
54             } 
55             if (b[i]<f[i]){
56                 for (int j=i+1;j<=f[i]-1;j++)
57                     w[j]=f[i];
58                 continue;
59             }
60             if (w[i]<f[i]){
61                 for (int j=i+1;j<=f[i]-1;j++)
62                     b[j]=f[i];
63                 continue;   
64             }
65             if (b[i]>w[i]){
66                 for (int j=i+1;j<=f[i]-1;j++)
67                     w[j]=f[i];
68             } else {
69                 for (int j=i+1;j<=f[i]-1;j++)
70                     b[j]=f[i];
71             }
72         }
73         //for (int i=1;i<=n;i++) cout<<f[i]<<" "<<b[i]<<" "<<w[i]<<endl;
74         if (flag) cout<<"sane"<<endl;
75         else cout<<"non"<<endl;
76     }
77     return 0;
78 }
View Code

T2都市环游

时间限制: 1 Sec  内存限制: 512 MB

题目描述

因为SJY干的奇怪事情过多,SJY收到了休假的通知,于是他准备在都市间来回旅游。SJY有一辆车子,一开始行驶性能为0,每过1时间行驶性能就会提升1点。每个城市的道路都有性能要求。SJY一共有t时间休息,一开始他位于1号城市(保证1号城市道路要求为0),他希望在n号城市结束旅程。每次穿过一条城市间的路会花费1时间,当然他也可以停留在一个城市不动而花费1时间。当且仅当车子的行驶性能大于等于一个城市,我们才能到达那里。SJY希望知道,旅游的方案模10086后的答案。(只要在某一时刻通过的道路存在一条不相同,就算不同的方案)

输入

    第一行三个数n,m,t,表示有n个城市m条道路t时间。
    第二行n个数,hi表示第i个城市的道路性能要求。
第三到m+2行,每行两个数u,v,表示城市u与城市v之间有一条单向道路连接(可能有重边)。

输出

包括一个数字,表示旅游的方案模10086。

样例输入

5 17 7
0 2 4 5 3
1 2
2 1
1 3
3 1
1 4
4 1
4 5
5 4
5 3
4 1
2 1
5 3
2 1
2 1
1 2
2 1
1 3

样例输出

245

提示

 

【数据规模和约定】

    对于20%的数据,n<=10,t<=80;

    对于50%的数据,n<=30,t<=80;

    对于100%的数据,n<=70,m<=1000,t<=100000000,hi<=70。
暴力dp小数据(有限制的)+利用矩阵快速幂优化矩阵乘法。
 1 #include<iostream> 
 2 #include<algorithm> 
 3 #include<cstdio> 
 4 #include<cstring> 
 5 #include<cmath> 
 6 #include<cstdlib> 
 7 #include<vector> 
 8 using namespace std; 
 9 typedef long long ll; 
10 typedef long double ld; 
11 typedef pair<int,int> pr; 
12 const double pi=acos(-1); 
13 #define rep(i,a,n) for(int i=a;i<=n;i++) 
14 #define per(i,n,a) for(int i=n;i>=a;i--) 
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i]) 
16 #define clr(a) memset(a,0,sizeof(a)) 
17 #define pb push_back 
18 #define mp make_pair 
19 #define fi first 
20 #define sc second 
21 #define pq priority_queue 
22 #define pqb priority_queue <int, vector<int>, less<int> > 
23 #define pqs priority_queue <int, vector<int>, greater<int> > 
24 #define vec vector 
25 ld eps=1e-9; 
26 ll pp=10086; 
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;} 
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;} 
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } 
30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; } 
31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1}; 
32 ll read(){ ll ans=0; char last=' ',ch=getchar(); 
33 while(ch<'0' || ch>'9')last=ch,ch=getchar(); 
34 while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar(); 
35 if(last=='-')ans=-ans; return ans; 
36 }
37 int map[100][100],f[105][105],h[100],n,m,t,ans;
38 struct M{ 
39     ll x[100][100]; 
40     M (){ 
41         memset(x,0,sizeof(x)); 
42     } 
43     friend M operator *(M a,M b){ 
44         M c; 
45         for (int i=1;i<=n;i++) 
46           for (int j=1;j<=n;j++) 
47             for (int k=1;k<=n;k++) 
48               c.x[i][j]=mo(c.x[i][j]+a.x[i][k]*b.x[k][j],pp); 
49         return c; 
50     } 
51     friend M operator ^(M a,int b){ 
52         M ans; 
53         for (int i=1;i<=n;i++) ans.x[i][i]=1; 
54         for (;b;b>>=1,a=a*a) 
55           if (b&1) ans=ans*a; 
56         return ans; 
57     } 
58 }A; 
59  
60 int main(){
61     n=read(),m=read(),t=read();
62     for (int i=1;i<=n;i++) h[i]=read(),map[i][i]=1;
63     for (int i=1;i<=m;i++){
64         int x=read(),y=read();
65         map[x][y]++;
66     }
67     f[0][1]=1;
68     for (int i=1;i<=min(100,t);i++)
69         for (int j=1;j<=n;j++) 
70         if (i>=h[j]){
71             for (int k=1;k<=n;k++)
72             if (map[k][j]){
73                 f[i][j]=mo(f[i][j]+f[i-1][k]*map[k][j],pp);
74             }
75         }
76     for (int i=1;i<=n;i++)
77         for (int j=1;j<=n;j++)
78             A.x[i][j]=map[i][j];
79     if (t>100) {
80     A=A^(t-100);
81     for (int i=1;i<=n;i++)
82         ans=mo(ans+(f[100][i]*A.x[i][n]),pp);
83     cout<<ans<<endl;
84     }
85     else cout<<f[t][n]<<endl;
86     return 0;
87 }
View Code

 

T3大水题

时间限制: 1 Sec  内存限制: 512 MB

题目描述

    dzy 定义一个n^2 位的数的生成矩阵A 为一个大小为n*n 且Aij 为这个数的第i*n+j-n位的矩阵。
现在dzy 有一个数n^2 位的数k,他想知道所有小于等于k 的数的n*n 生成矩阵有多少种。(如果不足n^2 位则补前缀零)

输入

第一行一个数n,第二行一个n^2 位的数k

输出

仅一行表示答案,答案可能很大,你只需输出答案对10^9 + 7 取模后的结果。

样例输入

2 1000

样例输出

954

提示

 

【数据规模和约定】 

对于30% 的数据n<=2

对于100% 的数据n <=1000,且n为偶数

 

【提示】

    如果两个生成矩阵在其中一个旋转180 度后可以重叠,则称这两个矩阵是相同的。
%%%LZW:
(From LZW):
  以前的模拟题今天被虐了。。。。好久没写博了更一下吧。。
  实际上直接可以当作一个n*n位的整数处理。
  设F(I)为i翻转后的数。
    答案可以分为3部分求:
    一是小于等于k的数的个数(设为S1)。
    二是小于等于k且翻转后的数也小于等于k的数个数(设为S2)。
    三是小于等于k且等于自身翻转的数的个数(设为S3)。
    于是
    这三部分可以用数位dp求出:
    设x为Ans=k−(ki=1[f[i](1,k)]ki=1[f[i]==i])/2=S1(S2S3)/2
    dp[i][j][p]表示枚举的整数在
    1.当前处理到第i位(这一维可以滚动的);
    2.j为一个01变量,标记创造的整数前一段长度为i的部分是小于(0)还是等于(1)k的前一部分;
    3.p表示这一段数翻转后小于等于(0)还是大于(1)原数的后一部分;
    状态下的合法个数。
    状态转移方程比较麻烦,细节比较多吧,注意一下各个状态之间的关系就行了,所以具体不多说了(好吧我比较懒。。)
    于是  S1=k
        S2=dp[n][0][0]+dp[n][1][0]
        S3=dp[n/2][0][0]+dp[n/2][0][1]+dp[n/2][1][0]
    最后代入原式即可求得答案。
 代码:
 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<int,int> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 #define vec vector
25 ld eps=1e-9;
26 ll mo=1000000007;
27 //ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
28 //ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; }
31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
32 ll read(){ ll ans=0; char last=' ',ch=getchar();
33 while(ch<'0' || ch>'9')last=ch,ch=getchar();
34 while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
35 if(last=='-')ans=-ans; return ans;
36 }
37 #define N 1000005
38 char ch[N];
39 long long dp[N][2][2],a[N],s1,s2,s3;
40 int main(){
41     int n=read(); n*=n; scanf("%s",ch+1);
42     for (int i=1;i<=n;i++){
43         a[i]=ch[i]-'0';
44     }
45     dp[0][1][0]=1;
46     for (int i=0;i<n;i++)
47         for (int j=0;j<2;j++)
48             for (int k=0;k<2;k++){
49                 if (j==0)    s1=10; else s1=a[i+1];
50                 if (k==0)    s2=a[n-i]+1; else s2=a[n-i];
51                 dp[i+1][0][0]=(dp[i+1][0][0]+(ll)dp[i][j][k]*min(s1,s2)%mo)%mo;
52                 if (j==1 && s2>a[i+1])    dp[i+1][1][0]=(dp[i][j][k]+dp[i+1][1][0])%mo;
53                 dp[i+1][0][1]=(dp[i+1][0][1]+(ll)dp[i][j][k]*max(0LL,s1-s2)%mo)%mo;
54                 if (j==1 && s2<=a[i+1])    dp[i+1][1][1]=(dp[i+1][1][1]+dp[i][j][k])%mo;
55             }
56     s1=((dp[n][0][0]+dp[n][0][1])%mo+(dp[n][1][0]+dp[n][1][1])%mo)%mo;
57     s2=(dp[n][0][0]+dp[n][1][0])%mo;
58     s3=((dp[n/2][0][0]+dp[n/2][1][0])%mo+dp[n/2][0][1])%mo;    
59     long long s=s1-(ll)(s2-s3)*((mo+1)/2)%mo-1;
60     cout<<(s%mo+mo)%mo<<endl;
61     return 0;
62 } 
View Code

 

posted @ 2017-07-09 14:22  SXia  阅读(336)  评论(0编辑  收藏  举报