C - Keine's Problem OpenJ_POJ - 1039

In Gensokyo, Keine is a teacher in Human Village. Since there are many naughty students in her class, Keine keeps a log of all in/out behaviors of all students, in chronological order.

Following is a part of an example log:

Cirno in 
Rumia in 
Cirno out 
Rumia out 

One day, Keine found that the log had been damaged. All the names of students were lost. Keine could remember that some of the records were relevant. Record u and record v are considered relevant if and only if:

  1. Record u and v are of the same student;

  2. Record u is 'I' and record v is 'O';

  3. Record u is before record v;

  4. No other record between record u and record v is of this student.

For example, the first record and the third record in the example log are relevant, since it was a log of Cirno entering and then exiting. However, there are still many possibilities for the whole log. Keine wants to know how many possible versions are there for the damaged log.

Notice that the classroom was empty at both the beginning and the ending of the log.

Input
The first line contains an integer T (1 ≤ T ≤ 1 000) -- the number of test cases. 

For each test case: 
The first line contains three integers: n, m, k. n (1 ≤ n ≤ 100 000) is the length of the log. m (1 ≤ m ≤ n/2) is the number of relevant pairs that Keine could remember. k (1 ≤ k ≤ 50) is the number of students who may appear in the log. 
The second line contains a string, which only consists of 'I' and 'O', indicates the in/out behaviors in the log. 
For next m lines, each line contains two integers u and v (u < v), indicate that the u-th and the v-th records are relevant. The u-th record must be 'I' and the v-th record must be 'O'.
Output
For each test case, output only an integer in a single line - the number of possible versions of the log, modulo (1 000 000 000+7).
Sample Input
3
8 2 3
IIOIOIOO
1 3
4 5
8 2 3
IIOOIOIO
2 3
5 6
6 2 3
IOIOIO
1 2
3 4
Sample Output
48
54
27


题意 还是很明确的,就是乘法原理,不过具体实现还要看理解的方式。

其中in表示在教室外面可以进教室的人数;

out表示在教室里面可以出来的人数;

经过这样的表示,就可以逐渐使用乘法原理实现了;

需要注意的是并不是每次进去教室out都要++,如果是在题目的m给出的要求中,那么out就不需要++,可以自行理解一下,很容易想明白。

具体上代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const long long mode = 1000000000+7;
int main()
{
	char s[100100];
	bool vis[100100];
	long long n,m,k;
	long long T;
	cin >> T; 
	while(T--)
	{
	 cin >> n >> m >> k;
	 scanf(" %s",s);	
	 memset(vis, false, sizeof(vis));
	 int a,b;
	 for(int i=1; i<=m; i++)
	 {
	   cin >> a >> b;
	   vis[a-1] = vis[b-1] = 1;
	 }
	 // 注意要用long long 类型 
	 long long in = k; //理解为刚开始有k人可以进教室 
	 long long out = 0; // 刚开始教室是空的,所以out=0; 
	 long long sum = 1; // 用来记数 
	 for(int i=0; i<n; i++)
	 {
	 	if(s[i]=='I')
	 	{	
	 	  sum = sum*in%mode; // 如果使进教室的话,那么有in个人可以进来 ,也就是有in种情况 
		  if(vis[i]==0) out++; // 如果没有指明要从哪个位置出来(也就是从那个‘O’出来都可以),那么out++; 
		  in--; // 有人进教室了,所以外面的人数in--; 
		}
		else
		{
		  if(vis[i]==0) // 原理同上,可以自行理解一下 
		  {
		    sum = sum*out%mode;	
		    out--;
		  }	
		  in++;
		}
     }	 	
     cout << sum%mode << endl; 
	}
 return 0;
} 
俺真菜.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值