题意:给定P,求P=A+B的对数并输出前5000项,其中A、B、P的数位两两不同
这个数位DP比较奇特。。难度还是比较大的。。过的人除了窝貌似都是该oj前10名
首先可以枚举A的数位和B的数位,然后根据这些数位做数位DP,这个数位DP的特殊之处在于这是2个数同时进行数位DP(其实枚举A的数位之后B的数位就只剩下2种情况了,从某种意义上讲也是单个数的数位DP),然后维护第几位,需不需要进位(毕竟加法有进位这个操作),还有就是A和B有没有出现首位等等,然后枚举A的数位去转移就可以了。。
这个部分的时间复杂度是,还行。。
然后麻烦的是输出前5000个。。这个可以直接把上面的数位DP搬下来,去掉记忆化,然后只枚举A的数位,得到补集直接作为B的数位,边搜边记录前5000个答案即可。。
然而如果不记忆化是能被卡掉的,只要能构造出刚好有大量低位的非法情况即可,比如1111111111这中不加记忆化会把1111111这些情况搜个遍,效率非常低。。所以还需要加个记忆化把0的情况给排掉。。。
/**
* ┏┓ ┏┓
* ┏┛┗━━━━━━━┛┗━━━┓
* ┃ ┃
* ┃ ━ ┃
* ┃ > < ┃
* ┃ ┃
* ┃... ⌒ ... ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃ Code is far away from bug with the animal protecting
* ┃ ┃ 神兽保佑,代码无bug
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#include<stdlib.h>
#include<assert.h>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 2005
#define nm 200005
#define pi 3.1415926535897931
const int inf=1e9;
using namespace std;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
ll n,d[20][2],s,ans[10001],cnt;
set<ll>a;
int tot,b[NM],tmp,c[20],e[20],n1,n2,f[NM],m,p;
bool v[10],_v[20][2];
ll dfs(int n,int t,bool f1,bool f2){
if(!n)return t==0;
if(f1&&f2&&_v[n][t])return d[n][t];
ll ans=0;
inc(i,f1,n1)if(!(!f1&&i&&c[i]==0))dec(j,n2,f2)if(!(!f2&&j&&e[j]==0)){
if(c[i]+e[j]==10*t+b[n])ans+=dfs(n-1,0,f1||i,f2||j);
else if(c[i]+e[j]==10*t+b[n]-1)ans+=dfs(n-1,1,f1||i,f2||j);
}
if(f1&&f2)_v[n][t]++,d[n][t]=ans;
return ans;
}
ll _dfs(int n,int t,bool f1,bool f2){
if(!n){if(t==0)ans[++m]=cnt;return t==0;}
if(f1&&f2&&_v[n][t]&&d[n][t]==0)return 0;
ll ans=0;
inc(i,f1,n1)if(!(!f1&&i&&c[i]==0))dec(j,n2,f2)if(!(!f2&&j&&e[j]==0)){
cnt=cnt*10+c[i];
if(c[i]+e[j]==10*t+b[n])ans+=_dfs(n-1,0,f1||i,f2||j);
else if(c[i]+e[j]==10*t+b[n]-1)ans+=_dfs(n-1,1,f1||i,f2||j);
cnt/=10;if(m==s)return 0;
}
if(f1&&f2)_v[n][t]++,d[n][t]=ans;
return ans;
}
void _solve(int x,int y){
n1=n2=0;c[0]=e[0]=0;m=0;mem(d);mem(_v);
inc(i,0,9)if(succ(i)&x)c[++n1]=i;
inc(i,0,9)if(succ(i)&y)e[++n2]=i;
_dfs(tot,0,0,0);
}
ll solve(int x,int y){
n1=n2=0;mem(d);mem(_v);c[0]=e[0]=0;
inc(i,0,9)if(succ(i)&x)c[++n1]=i;
inc(i,0,9)if(succ(i)&y)e[++n2]=i;
return dfs(tot,0,0,0);
}
int main(){
n=read();
for(ll x=n;x;x/=10)b[++tot]=x%10,v[x%10]++;
inc(i,0,9)if(v[i])tmp|=succ(i);
// s=10000;_solve(succ(5)+succ(0)+succ(6),succ(3)+succ(9)+succ(8));
inc(i,0,1023){
int s=0;
for(int t=i;t;t>>=1)if(t&1)s++;
f[i]=s;
}
inc(i,1,1023)if((i&tmp)==0)inc(j,1,1023)if((j&tmp)==0&&(i&j)==0){
s+=solve(i,j)*((f[i]+f[j])%2==0?1:-1);
}
s=abs(s)/2;
printf("%lld\n",s);
s=min(s,5000LL);
if(!s)return 0;
set<ll>::iterator it;
inc(i,1,1023)if((i&tmp)==0){
int j=1023-tmp-i;
_solve(i,j);
inc(k,1,m)if(!a.count(ans[k])){
if(a.size()<s)a.insert(ans[k]);
else{
it=a.end();it--;
if(*it>ans[k]){a.erase(it);a.insert(ans[k]);}
}
}
}
for(auto&j:a)printf("%lld %lld\n",j,n-j);
return 0;
}
ICPC NAQ 2016 F - Free Desserts
ICPC North America Qualifier 2016, Problem F
Quido has lunch in Hugo’s restaurant every day. He likes the restaurant because all of its prices are expressed as integers, and for each possible price (i.e. $ 1 \$1 , $ 2 \$2 , $ 3 \$3 , etc.) there is at least one beverage and at least one main dish on the menu. Every day there are three entries printed on Quido’s lunch bill: the beverage price, the main dish price, and the total price. Hugo knows of Quido’s interest in computational problems and he offered Quido a free dessert each time his lunch bill meets the following three constraints:
- the bill is not identical to any of Quido’s previous bills,
- the price of the beverage is less than the price of the main dish, and
- the prices listed on the bill cannot mutually use the same digit. In essence, any digit which occurs in any of the entries (beverage, main dish, total) must be different from any of the digits of the other two entries.
Quido is on a budget and he pays the same price for his lunch every day. How many times can he have a free dessert?
Input Specification
The input consists of a single line with one integer representing the price P P which Quido pays for each lunch. The value of P P is positive and less than 10 18 10^{18} ..
Output Specification
Output the maximum number of times Quido can have a free dessert at Hugo’s restaurant, provided that the price of his lunch is always P P . Next, the possible bills which result in a free dessert are listed in ascending order with respect to the beverage price. Each bill consists of the price of the beverage followed by the price of the main dish. For simplicity, the value P P , which is always the same, is not included in the bill.
If there are more than 5000 possible bills, then output only the first 5000 bills (but still report the total number of possible bills before the list of bills).
Sample Input 1
Copy
37
Sample Output 1
Copy
4
8 29
9 28
11 26
15 22
Sample Input 2
Copy
30014
Sample Output 2
Copy
7
85 29929
88 29926
785 29229
788 29226
7785 22229
7788 22226
7789 22225
Sample Input 3
Copy
202020202020202058
Sample Output 3
Copy
3
7676767676767667 194343434343434391
37373737373737397 164646464646464661
67676767676767667 134343434343434391