naq2016F(数位DP)

题意:给定P,求P=A+B的对数并输出前5000项,其中A、B、P的数位两两不同

这个数位DP比较奇特。。难度还是比较大的。。过的人除了窝貌似都是该oj前10名

首先可以枚举A的数位和B的数位,然后根据这些数位做数位DP,这个数位DP的特殊之处在于这是2个数同时进行数位DP(其实枚举A的数位之后B的数位就只剩下2种情况了,从某种意义上讲也是单个数的数位DP),然后维护第几位,需不需要进位(毕竟加法有进位这个操作),还有就是A和B有没有出现首位等等,然后枚举A的数位去转移就可以了。。

这个部分的时间复杂度是O(2^{10}2^{10}18*2),还行。。

然后麻烦的是输出前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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值