1. 程式人生 > >JZOJ 100027. 【NOIP2017提高A組模擬7.7】表示式

JZOJ 100027. 【NOIP2017提高A組模擬7.7】表示式

JZOJ 100027. 【NOIP2017提高A組模擬7.7】表示式

題目

Description

在這裡插入圖片描述

Input

一行兩個整數k,p。

Output

一行一個整數表示答案。

Sample Input

1 3

Sample Output

6

Data Constraint

對於20%的數: k p <

= 1 0 5 k*p<=10^5
對於另外20%的資料k=1。
對於70%的資料: k
p < = 1 0 9 k*p<=10^9

對於100%的資料:k,p<= 1
0 9 10^9

題解

方法一

在這裡插入圖片描述
在這裡插入圖片描述
(內容來源:https://jzoj.net

方法二

p = 2 p=2 ,答案為 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 1,0,1,0,1,0,1,0,1,0……
p = 3 p=3 ,答案為 6 , 6 , 0 , 6 , 6 , 0 , 6 , 6 , 0 6,6,0,6,6,0,6,6,0……
p = 5 p=5 ,答案為 15 , 10 , 10 , 15 , 0 , 15 , 10 , 10 , 15 , 0 15,10,10,15,0,15,10,10,15,0……
p = 7 p=7 ,答案為 28 , 14 , 7 , 7 , 14 , 28 , 0 , 28 , 14 , 7 , 7 , 14 , 28 , 0 28,14,7,7,14,28,0,28,14,7,7,14,28,0……
p = 11 p=11 ,答案為 66 , 22 , 110 , 88 , 77 , 77 , 88 , 110 , 22 , 66 , 0 66,22,110,88,77,77,88,110,22,66,0……
……
這樣好像看不出什麼,但可以發現兩點:
1、答案有迴圈,且每個迴圈節是迴文的, k p k|p 時答案為0.
2、 p &gt; 2 p&gt;2 時非 0 0 的答案為 p p 的倍數。
那麼我們把每個迴圈節前一半的答案除以 p p 找出來。
p = 3 p=3 2 2
p = 5 p=5 3 , 2 3,2
p = 7 p=7 4 , 2 , 1 4,2,1
p = 11 p=11 6 , 2 , 10 , 8 , 7 6,2,10,8,7
p = 13 p=13 7 , 2 , 11 , 8 , 6 , 5 7,2,11,8,6,5
p = 17 p=17 9 , 2 , 13 , 8 , 4 , 1 , 16 , 15 9,2,13,8,4,1,16,15
p = 23 p=23 12 , 2 , 16 , 8 , 1 , 18 , 13 , 9 , 6 , 4 , 3 12,2,16,8,1,18,13,9,6,4,3
……
通過觀察發現,每一行的第一項為 p + 1 2 \frac{p+1}{2}
後面的呢?
不難發現(其實很難),每一項為一個公差為 1 1 的等差數列的字首和,再對 p p 取模。
舉例:
p = 23 p=23 ,等差數列 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 12,13,14,15,16,17,18,19,20,21,22
p = 23 p=23 ,字首和 12 , 25 , 39 , 54 , 70 , 87 , 105 , 124 , 144 , 165 , 187 12,25,39,54,70,87,105,124,144,165,187
p = 23 p=23 ,對 p p 取模後 12 , 2 , 16 , 8 , 1 , 18 , 13 , 9 , 6 , 4 , 3 12,2,16,8,1,18,13,9,6,4,3
這樣就可以快速實現了,注意 p = 2 p=2 要特判。

程式碼

方法二的程式碼。

#include<cstdio>
#include<cstring>
using namespace std;
int main()
{
	int k,p;
	scanf("%d%d",&k,&p);
	if(p==2)
	{
		printf("%d",k%2);
		return 0;
	}
	k%=p;
	if(k==0)
	{
		printf("0");
		return 0;
	}
	if(k>p/2) k=p-k;
	long long s