jzoj 1434. 灌水

38 篇文章 0 订阅
32 篇文章 0 订阅

Description

  学生都很喜欢灌水,第一天只有Alice给她的每个朋友灌了一次水,从第二天开始,所有学生(包括Alice)将会有规律地去灌水:
  •如果前一天被灌了奇数次的水,他们将会给每个朋友灌一次水;
  •如果前一天被灌了偶数次的水,他们将会给每个朋友灌两次水。
  学生编号为1到N,Alice为1号,学生之间的朋友关系会给出。
  计算H天后一共灌了几次水。

Input

  输入一行包含两个整数N和H(1<=N<=20,1<=H<=10^9),表示学生数和天数。
  接下来N行,每行包含N个‘0’或‘1’,(A,B)处的字符表示A和B的关系,‘1’表示是朋友关系,‘0’表示不是。注意自己和自己不是朋友关系,输入保证该矩阵是对称的。

Output

  输出H天后一共灌水的数量。

Sample Input

输入1:
4 1
0110
1001
1001
0110

输入2:
4 2
0110
1001
1001
0110

输入3:
5 3
01000
10110
01000
01001
00010

Sample Output

输出1:
2

输出2:
14

输出3:
26

Data Constraint

Hint

【样例解释】
  样例2中,第一天Alice灌了2次水,第二天学生1和学生4给学生2和学生3都灌了2次水,而学生2和学生3给学生1和学生4各灌水1次,2天一共灌了12次水。
【数据范围】
  50%的数据 H<=1000。

正解

因为H这么大,我们一想就能想到肯定有规律可循。我们可以发现,当这个序列经过一定的次数后,全都是偶数,这时就开始循环了。我们只用记录它的状态、时间,去找循环节即可。

CODE

var
        ji:array[0..30,0..100000]of longint;
        sum,bz:array[0..1000010]of int64;
		a,new:array[0..100000]of longint;
        ans,ans1,bz1:int64;
        n,m,i,j,k:longint;
        ch:char;
begin
        readln(n,m);
        for i:=1 to n do begin
                for j:=1 to n do begin
                        read(ch);

                        if ch='1' then begin
                                inc(ji[i,0]);
                                ji[i,ji[i,0]]:=j;
                        end;
                end;
                readln;
        end;
        for i:=1 to ji[1,0] do a[ji[1,i]]:=1;
        sum[1]:=ji[1,0];
        for i:=1 to n do
                if odd(a[i]) then ans:=ans+1 shl (i-1);
        bz[ans]:=1;
        for i:=2 to m do begin
                bz1:=0;ans:=0;ans1:=0;
                for j:=1 to n do begin
                        if a[j] mod 2=0 then begin
                                ans:=ans+ji[j,0]*2;
                                for k:=1 to ji[j,0] do inc(new[ji[j,k]],2);
                        end
                        else begin
                                ans:=ans+ji[j,0];
                                for k:=1 to ji[j,0] do inc(new[ji[j,k]]);
                        end;
                end;
                for j:=1 to n do begin
                        a[j]:=new[j];
                        new[j]:=0;
                        if odd(a[j]) then ans1:=ans1+1 shl (j-1);
                end;
                sum[i]:=sum[i-1]+ans;
                if bz[ans1]<>0 then begin
                        ans:=(m-bz[ans1]) div (i-bz[ans1])*(sum[i]-sum[bz[ans1]]);
                        ans:=ans+sum[bz[ans1]+(m-bz[ans1]) mod (i-bz[ans1])];
                        writeln(ans);
                        halt;
                end
                else bz[ans1]:=i;
        end;
        writeln(sum[m]);
end.

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值