第38次CCFCSP第三题--消息解码
题目:
思路:
纯大模拟+高精度二进制乘法(可能不需要?我用了,比较保险)
这种题就是一个“不畏难”+“细心”,其实做着真不难。建议做个简略的笔记,详细列出每一种情况。理解是难点,写代码就很快了
代码:
#include<bits/stdc++.h>
#include<queue>
#include<string>
#include<stack>
#include<vector>
#include<map>
#include<unordered_map>
#include<set>
#include<iostream>
#define maxn 105
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
#define ll unsigned long long
#define mod 1000000007
using namespace std;
int n;
int message[73];
double C=47055833459;
map<int,string>m12,m25;
int short_cof[6]={6327360,175760,17576,676,26,1};
ll long_cof[13];
struct node{int d[100];int len=0;
};
ll qpow(ll a,ll b){ll res=1;while(b){if(b&1)res*=a;a*=a;b>>=1;}return res;
}
node tob(ll v){node res;mem(res.d,0);int pos=0;while(v){res.d[pos++]=v%2;v>>=1;}res.len=pos;return res;
}
node mul(node a,node b){node c;mem(c.d,0);int lenc=a.len+b.len+2;for(int i=0;i<a.len;i++)for(int j=0;j<b.len;j++){c.d[i+j]+=a.d[i]*b.d[j];}for(int i=0;i<lenc;i++)c.d[i+1]+=c.d[i]/2,c.d[i]%=2;while(c.d[lenc]==0&&lenc>0)lenc--;c.len=lenc+1;return c;
}
node rshift(node a,int v){for(int i=0;i<a.len;i++)if(i+v<99)a.d[i]=a.d[i+v];else a.d[i]=0;a.len=max(1,a.len-v);return a;
}
ll tonum(int s,int t){ll res=0;for(int i=s;i<=t;i++)res=res*2+message[i];return res;
}
ll btonum(node a){ll res=0;for(int i=a.len-1;i>=0;i--)res=res*2+a.d[i];return res;
}
string parse_short_code(int v){int tem[7];string res="";v-=(1<<25);for(int i=1;i<=6;i++){tem[i]=v/short_cof[i-1];v%=short_cof[i-1];}if(tem[1]==0);//什么也不做else if(tem[1]<=10)res+='0'+(tem[1]-1);else res+='A'+(tem[1]-11);if(tem[2]<=9)res+='0'+(tem[2]);else res+='A'+(tem[2]-10);res+='0'+tem[3];res+='A'+tem[4];res+='A'+tem[5];res+='A'+tem[6];return res;
}
ll sanlie(string code,int b){//必须是无空格的代码表示形式int cnt=10;ll res=0;for(auto &ch:code){if(ch>='0'&&ch<='9')res+=1ll*(ch-'0'+1)*qpow(38,cnt);else if(ch>='A'&&ch<='Z')res+=1ll*(ch-'A'+11)*qpow(38,cnt);else res+=37*1ll*qpow(38,cnt);cnt--;}node rr=mul(tob(res),tob(C));rr=rshift(rr,64-b);ll x=btonum(rr);return x%(1<<b);
}
string parse25(int v){if(v>=(1<<25)){//短代码,还要添加至数据库string res=parse_short_code(v);return res;}else {//散列值auto it=m25.find(v);if(it==m25.end())return "###";else return "#"+it->second;}
}
string parse_full_code(ll v){string res="";for(int i=1;i<=11;i++){int val=v/long_cof[i];v%=long_cof[i];if(val==0)break;else if(val<=10)res+='0'+val-1;else if(val<=36)res+='A'+val-11;else res+="_";} return res;
}
string parse12(int v){auto it=m12.find(v);if(it==m12.end())return "###";return "#"+it->second;
}
void parse_easy(void){int v1=tonum(2,29);int v2=tonum(30,57);int pos=tonum(58,72);string r1=parse25(v1);//接收方string r2=parse25(v2);//发送方if(r1[0]!='#'){m25[sanlie(r1,25)]=r1;m12[sanlie(r1,12)]=r1;}if(r2[0]!='#'){m25[sanlie(r2,25)]=r2;m12[sanlie(r2,12)]=r2;}if(pos==0)cout<<r1<<" "<<r2<<endl;else cout<<r1<<" "<<r2<<" "<<pos<<endl;
}
void parse_hard(void){ll v1=tonum(2,59);ll v2=tonum(60,71);string r1=parse_full_code(v1);string r2=parse12(v2);m25[sanlie(r1,25)]=r1;m12[sanlie(r1,12)]=r1;if(message[72]==0)swap(r1,r2);cout<<r1<<" "<<r2<<endl;
}
void init(void){for(int i=10;i>=0;i--)long_cof[11-i]=qpow(38,i);
}
int main()
{scanf("%d",&n);init();while(n--){for(int i=1;i<=72;i++)scanf("%1d",&message[i]);if(message[1]==0)parse_easy();else parse_hard();}return 0;
}