1. 程式人生 > 實用技巧 >NOIP2016普及組

NOIP2016普及組

T2

迴文日期

題目描述】

日常生活中,通過年、月、日這三個要素可以表示出一個唯一確定的日期。

牛牛習慣用88位數字表示一個日期,其中,前44位代表年份,接下來22位代表月份,最後22位代表日期。顯然:一個日期只有一種表示方法,而兩個不同的日期的表示方法不會相同。

牛牛認為,一個日期是迴文的,當且僅當表示這個日期的88位數字是迴文的。現在,牛牛想知道:在他指定的兩個日期之間(包含這兩個日期本身),有多少個真實存在的日期是迴文的。

【提示】

一個88位數字是迴文的,當且僅當對於所有的i(1<i<8)i(1<i<8)從左向右數的第ii個數字和第9i9−i個數字(即從右向左數的第

ii個數字)是相同的。

例如:

·對於2016年11月19日,用88位數字2016111920161119表示,它不是迴文的。

·對於2010年1月2日,用88位數字2010010220100102表示,它是迴文的。

·對於2010年10月2日,用88位數字2010100220101002表示,它不是迴文的。

每一年中都有12個月份:

其中,11,33,55,77,88,1010,1212月每個月有3131天;44,66,99,1111月每個月有3030天;而對於22月,閏年時有2929天,平年時有2828天。

一個年份是閏年當且僅當它滿足下列兩種情況其中的一種:

1.這個年份是44的整數倍,但不是100100的整數倍;

2.這個年份是400400的整數倍。

例如:

·以下幾個年份都是閏年:20002000,20122012,20162016

·以下幾個年份是平年:19001900,20112011,2014

【這個很簡單,但是不是一個一個挨著判斷的,而是直接根據每一年的年數去創造這個迴文串,然後判斷是不是迴文串】

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1010;
const int INF=0x3fffffff;
int d1,d2; 
int rev(int x){
	int op=0;
	while(x){
		op=op*10+x%10;
		x/=10;
	}
	return op;
}
bool judge(int year,int x){
	if(x/100>12) return 0;
	if(x%100>31) return 0;
	int month=x/100,day=x%100;
	if(month==1||month==3||month==5||month==7||month==8||month==10||month==12) {
		if(day<=31) return 1;
		else return 0;
	}
	if(month==4||month==6||month==9||month==11) {
		if(day<=30) return 1;
		else return 0;
	}
	if(month==2){
		if(year%400==0||(year%4==0&&year%100!=0)){
			if(day<=29) return 1;
			else return 0;
	}
	else{
		if(day<=28) return 1;
		else return 0;
	}
	}
}
int main(){
	cin>>d1>>d2;
	int y1=d1/10000,y2=d2/10000;
	int ans=0;
	int fan1=0,temp=y1;
	fan1=rev(temp);
	while(y1<=y2){
		if(judge(y1,fan1)&&(y1*10000+fan1)<=d2&&(y1*10000+fan1)>=d1) {
			ans++;
			//cout<<y1*10000+fan1<<endl;
		}
		y1++;
		fan1=rev(y1);
	}
	cout<<ans<<endl;
return 0;
}

  

T4 魔法陣

//我沒有想到的方法。。。首先畫圖,看一下資料的分佈,(同時看題目給出的資料範圍,會有許多重複的資料)
//然後設定迴圈的引數:c和l(c和d之間的間隙),會發現規律,b與a之間的間隙是2l,b與c之間的間隙至少有6l,所以總的迴圈就減少到了n/9
//a,b的求法和c,d是一樣的

這裡有兩個迴圈,分別是針對d和b的,因為中間的6l是不確定的,但是在迴圈裡面是確定的,所以要控制這兩個資料的迴圈。

從而分別用陣列來儲存這個物體作為a,b,c,d的情況數,res[m][4]

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1010;
const int INF=0x3fffffff;
int n,m;
int x[40010],vis[40010],res[40010][4]; 
 
 
int a[40001];
int main(){
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d",&x[i]);
		vis[x[i]]++;
	}
	int ans=0;
	for(int l=1;l<=n/9;l++){ //迴圈間隙 
	ans=0; 
		for(int d=9*l;d<=n;d++){ //求c,d 
			int c=d-l;
			int b=c-6*l-1;
			ans+=vis[b-2*l]*vis[b]; //a,b的乘數
			res[c][2]+=ans*vis[d];
			res[d][3]+=ans*vis[c]; 
		}
	}
	for(int l=1;l<=n/9;l++){
		ans=0;
		for(int b=n-7*l-1;b>=2*l+1;b--){ //從後往前列舉 
			int a=b-2*l;
			int c=b+6*l+1;
			ans+=vis[c]*vis[c+l];
			res[a][0]+=ans*vis[b];
			res[b][1]+=ans*vis[a];
		}
	}
	for(int i=1;i<=m;i++){
		for(int j=0;j<4;j++){
			printf("%d",res[x[i]][j]);
			if(j<3) printf(" ");
		}
		printf("\n");
	}
return 0;
}

/*
30 8
1 24 7 28 5 29 26 24
*/