【纪中受难记】——Day1:没有爆零

上午考完感觉心情一般般,第二题貌似可以打表但是没打,自认为是“简单的模拟题”,其他题没动。

下午出来:0/36.4/0,十分心痛。

果然,菜就是原罪。


1.游戏

Description

Alice和Bob在玩一个游戏,游戏是在一个N*N的矩阵上进行的,每个格子上都有

一个正整数。当轮到Alice/Bob时,他/她可以选择最后一列或最后一行,并将其删除,但

必须保证选择的这一行或这一列所有数的和为偶数。如果他/她不能删除最后一行或最后一

列,那么他/她就输了。两人都用最优策略来玩游戏,Alice先手,问Alice是否可以必胜?

 

Input

第一行:T,表示数据组数

对于每组数据的第一行:N

接下来N行,每行N个数,描述这个矩阵

Output

如果Alice必胜输出W,否则输出L

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

这就是一道简单的递推。

首先分析一下状态,我们用增加一行/一列的方法考虑。

1.最开始的状态是由一个数组成的,要么是奇数要么是偶数,因为只能拿偶数,所以偶即赢,奇即输,分别用1(先手必赢)和0(先手必输)表示。

2.不断扩充状态,我们发现只要考虑增加的一行或者一列的和为奇还是偶,用前缀和来表示,如果为奇,则不考虑这行/列。

  之后会出现几种情况:

  1|0,1|1,0|0,1|-,0|-,0|0(|号表示分隔行和列)

  发现两边都有的情况下只要取!(a&b)即可,只有一边则取该边的异或。

3.列递推式即可解决。

 

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int N=1e3+10;
 6 int t,sumh[N][N],sums[N][N],a[N][N],state[N][N];
 7 int n;
 8 int main(){
 9     scanf("%d",&t);
10     for(int q=1;q<=t;q++){
11         memset(sumh,0,sizeof(sumh));
12         memset(sums,0,sizeof(sums));
13         memset(a,0,sizeof(a));
14         memset(state,0,sizeof(state));
15         scanf("%d",&n);
16         for(int i=1;i<=n;i++){
17             for(int j=1;j<=n;j++){
18                 scanf("%d",&a[i][j]);
19                 sumh[i][j]=sumh[i][j-1]+a[i][j];
20                 sums[i][j]=sums[i-1][j]+a[i][j];
21             }
22         }
23         state[1][1]=a[1][1]%2==0?1:0;
24         for(int i=1;i<=n;i++){
25             for(int j=1;j<=n;j++){
26                 int sh=sumh[i][j]%2==0?0:1;
27                 int ss=sums[i][j]%2==0?0:1;
28                 if(sh&&ss) state[i][j]=0;
29                 else if(sh&&!ss) state[i][j]=state[i][j-1]^1;
30                 else if(!sh&&ss) state[i][j]=state[i-1][j]^1;
31                 else state[i][j]=!(state[i-1][j]&state[i][j-1]);
32             }
33         }
34         if(state[n][n]==1) cout<<"W"<<endl;
35         else cout<<"L"<<endl;
36     }
37     return 0;
38 //    for(int i=1;i<=n;i++){
39 //        for(int j=1;j<=n;j++){
40 //            printf("%d ",a[i][j]);
41 //        }
42 //        cout<<endl;
43 //    }
44 //    for(int i=1;i<=n;i++){
45 //        for(int j=1;j<=n;j++){
46 //            printf("%d ",sumh[i][j]);
47 //        }
48 //        cout<<endl;
49 //    }for(int i=1;i<=n;i++){
50 //        for(int j=1;j<=n;j++){
51 //            printf("%d ",sums[i][j]);
52 //        }
53 //        cout<<endl;
54 //    }
55 }

 

 

 


 

2.六边形

Description

棋盘是由许多个六边形构成的,共有5种不同的六边形编号为1到5,棋盘的生成规

则如下:

1.从中心的一个六边形开始,逆时针向外生成一个个六边形。

2.对于刚生成的一个六边形,我们要确定它的种类,它的种类必须满足与已生成的相

邻的六边形不同。

3.如果有多个种类可以选,我们选择出现次数最少的种类。

4.情况3下还有多个种类可以选,我们选择数字编号最小的。

现在要你求第N个生成的六边形的编号?

前14个六边形生成图如下:


 

Input

第一行:T,表示数据组数

接下来T行,每行一个数:N,表示第N个六边形

Output

共t行,每行一个数,表示第N个数据的答案

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 这是坑到我的“简单的模拟”。

1.找出一个点i需要与之判断的相邻点:

  (1)点i-1

  (2)内圈的一个或两个点。

  (3)如果是每圈的最后一个点,则要与每圈的第一个点判断。

  (4)如果是每圈的第一个点,则要与上一圈的第一点和最后一个点判断。(这点很重要)

2.模拟,也可以打表解决。

错误范例:

 

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 typedef long long ll;
 6 const ll N=1e5+10;
 7 ll n,a[N],six[N],ang[N],change[N],cag[N],q[6];
 8 ll cen(ll x){
 9     return (x-1)/6;
10 }
11 void init(){
12     six[1]=6,ang[1]=1,cag[1]=1;change[1]=0;
13     for(ll i=2;i<=11000;i++){
14         six[i]=i*6;
15         ang[i]=ang[i-1]+six[i-1];
16         if(ang[i]<=11000) cag[ang[i]]=i;
17     }
18     for(ll i=1,j=1;i<=11000;i++){
19         if(!cag[i]) cag[i]=j;
20         else cag[i]=j++;
21     }
22     for(ll i=1;ang[i]<=11000;i++){//ang1=1,ang2=7,ang3=19(ch1=0,ch7=6,ch19=12)
23         change[ang[i]]=six[cag[ang[i]]-1];
24         for(ll j=1;j<=5;j++){
25             change[ang[i]+j*cag[ang[i]]]=change[ang[i]]+j;
26         }
27     }
28 }
29 ll fch(ll x){
30     while(change[x])x++;
31     return change[x];    
32 }
33 int main(){
34 //    freopen("in.txt","r",stdin);
35     init();
36     scanf("%lld",&n);
37     a[1]=1,a[2]=2,a[3]=3,a[4]=4,a[5]=5,a[6]=2,a[7]=3,a[8]=1,a[9]=4,a[10]=5,a[11]=1,a[12]=2,a[13]=3,a[14]=1;
38     q[1]=4,q[2]=3,q[3]=3,q[4]=2,q[5]=2;
39     for(ll i=15;i<=11000;i++){
40         ll minn=1000000,minnum=0;
41         ll judge[6];
42         memset(judge,0,sizeof(judge));
43         judge[a[i-1]]=1;
44         if(change[i]){
45             judge[a[i-change[i]]]=1;
46             if(change[i]%6==0) judge[a[i-change[i]+1]]=1;
47         }
48         else if(change[i-1]&&change[i-1]%6==0){
49             judge[a[i-1]]=1;
50             judge[a[i-change[i-1]+1]]=1;
51         } 
52         else{
53             judge[a[i-fch(i)]]=1;
54             judge[a[i-fch(i)+1]]=1;
55         }
56         for(ll j=1;j<=5;j++){
57             if(judge[j]) continue;
58             if(q[j]<minn){
59                 minn=q[j];
60                 minnum=j;
61             }
62         }
63         a[i]=minnum;
64         q[minnum]++;
65 //        if(i==100){
66 //            for(int i=1;i<=5;i++) cout<<judge[i]<<" ";
67 //            cout<<endl;
68 //            cout<<ang[i]<<" "<<minnum<<" "<<minn<<" "<<fch(i)<<" "<<change[i]<<endl;
69 //        }
70     }
71     for(ll i=1,wer;i<=n;i++){
72         scanf("%lld",&wer);
73         printf("%lld\n",a[wer]);
74     }
75 //    for(ll i=1;i<=100;i++) cout<<six[i]<<" ";
76 //    cout<<endl;
77 //    for(ll i=1;i<=100;i++) cout<<ang[i]<<" ";
78 //    cout<<endl;
79 //    for(ll i=1;i<=100;i++) cout<<cag[i]<<" ";
80 //    cout<<endl;
81 //    for(ll i=1;i<=100;i++) cout<<i<<" "<<change[i]<<endl;
82 //    cout<<endl;
83     return 0;
84 }

 

找空改吧。

 


 

3.数列

Description

给你一个长度为N的正整数序列,如果一个连续的子序列,子序列的和能够被K整

除,那么就视此子序列合法,求原序列包括多少个合法的连续子序列?

对于一个长度为8的序列,K=4的情况:2, 1, 2, 1, 1, 2, 1, 2 。它的答案为6,子序列

是位置1->位置8,2->4,2->7,3->5,4->6,5->7。

 

Input

第一行:T,表示数据组数

对于每组数据:

第一行:2个数,K,N

第二行:N个数,表示这个序列

Output

共T行,每行一个数表示答案

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

这道题目有两种解法:

解法1:前缀和同余

一段骚操作之后,我们将前缀和处理出来,按照从小到大排个序;

然后我们数相同的数字,因为在原排列中,任取两个相同数字间的一段都是k的倍数,所以这样的段共有  个。

所以,数数字就行了(笑)。

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 typedef long long ll;
 7 const ll N=5e5+10;
 8 ll t,k,n,a[N],ans;
 9 ll c(ll m,ll n){
10     ll ans=1;
11     for(ll i=m,j=1;j<=n;j++,i--) ans*=i;
12     for(ll i=1;i<=n;i++) ans/=i;
13     return ans;
14 }
15 int main(){
16     scanf("%lld",&t);
17     for(ll q=1;q<=t;q++){
18         memset(a,0,sizeof(a));
19         ans=0;
20         scanf("%lld%lld",&k,&n);
21         ll p;
22         for(ll i=1;i<=n;i++){
23             scanf("%lld",&p);
24             a[i]=(a[i-1]+p)%k;
25         }
26         sort(a+1,a+n+1);
27         ll s=1;
28         for(ll i=1;i<=n;i++){
29             if(a[i]==a[i-1]) s++;
30             else{
31                 ans+=c(s,2);
32                 s=1;
33             } 
34         }
35         ans+=c(s,2);
36         printf("%lld\n",ans);
37     }
38     return 0;
39 }

 

 

 

解法2:分治:

一分为二,处理过中间线的部分即可。


总结:

第一天过得很充实,虽然分数不高,但捡了很多忘掉的知识,所以明天继续加油啦!

(qwq我想看mea直播)

 

posted @ 2019-08-01 19:03  Nelson992770019  阅读(230)  评论(0编辑  收藏  举报