[USACO2.2]序言頁碼 Preface Numbering
阿新 • • 發佈:2018-12-01
連結
大意
求
所有羅馬數字各個字母的出現次數。
思路
直接暴力,不過這題噁心的地方在於可能有這樣的 等帶減號的,我們也把它們編入字典,然後特判即可
時間複雜度:
洛谷上有位 用數位 做的,本蒟蒻太菜不會,各位大佬可以自行借鑑。
程式碼
/*
ID:hzbismy1
LANG:C++
TASK:preface
*/
#define file(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout)
#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;int b[7],n;//b表示對應字母的出現次數
const int a[14]={4000,1000,900,500,400,100,90,50,40,10,9,5,4,1};//表示字典
const char c[7]={'M','D','C','L','X','V','I'};//表示字母
inline char Getchar()
{
static char buf[100000],*p1=buf+100000,*pend=buf+100000;
if(p1==pend)
{
p1=buf; pend=buf+fread(buf,1,100000,stdin);
if (pend==p1) return -1;
}
return *p1++;
}
inline int read()
{
char c;int d=1,f=0;
while(c=Getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=Getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
inline void write(register long long x)
{
if(x<0)write(45),x=-x;
if(x>9)write(x/10);
putchar(x%10+48);
return;
}//以上為輸入輸出優化
inline void add(register int x)
{
int k;
while(x>0)
{
for(register int i=1;i<=13;i++)
if(x<a[i-1]&&x>=a[i])
{
x-=a[i];
b[(i-1)>>1]++;//把所有數看做兩個一組
if(!(i&1)) b[(i>>1)+((i>>1)&1)]++;//找規律推出來的,本人是這樣推的:
/*我們發現所有帶減號的符號的序號都是偶數的,所以有!(i&1)
然後,發現序號和相減的編號是這樣的
2 2 4 4 6 6
2 4 6 8 10 12
發現下方是一個等差數列,我們把它除以2
2 2 4 4 6 6
1 2 3 4 5 6
發現偶數項是相等的,奇數項加了1,就有了(i>>1)+(i>>1)&1
因為本人是一個蒟蒻,不太懂位運算的優先順序,所以只好乖乖的加了括號
*/
}
}
return;
}
signed main()
{
file(preface);
n=read();
for(register int i=1;i<=n;i++) add(i);//預處理
for(register int i=6;i>=0;i--)
if(b[i]) putchar(c[i]),putchar(32),write(b[i]),putchar(10);//輸出
}