A
暴力跑 模拟分母
#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
//2147483647
using namespace std;
typedef long long ll;
typedef pair<double, double> PII;
ll n,m,k;
ll cnt=0,sum=0;
ll ans=0;
ll mod=1e9+7;
const int maxn=1e6+199;
ll x,y;char a[100];
int main(){
while(cin>>n){
if(n==0) break;
int c=1233;
int flag=0;
while(c++){
int b=c*n;
sprintf(a,"%05d%05d",b,c);
if(strlen(a)>10)
break;
int pre[200];
memset(pre,0,sizeof(pre));
int i=0;
for(i=0;i<10;i++){
if(pre[a[i]-'0']) break;
pre[a[i]-'0']++;
}
if(i==10)
{
printf("%05d / %05d = %lld\n",b,c,n);
flag=1;
}
}
if(!flag){
printf("There are no solutions for %d.\n",n);
}
putchar('\n');
}
return 0;
}
B
找连续子序列最大乘机
两个for模拟即可
#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
//2147483647
using namespace std;
typedef long long ll;
typedef pair<double, double> PII;
ll n,m,k;
ll cnt=0,sum=0;
ll ans=0;
ll mod=1e9+7;
const int maxn=1e6+199;
ll x,y;ll a[maxn];
ll gcd(int x,int y){
if(x%y==0)
return y;
return gcd(y,x%y);
}
int main(){
while(cin>>n){
for(int i=1;i<=n;i++) cin>>a[i];
ll maxl=0;
for(int i=1;i<=n;i++){
ll sum=1;
for(int j=i;j<=n;j++){
sum*=a[j];
maxl=max(maxl,sum);
}
}
cout<<"Case #"<<++cnt<<": The maximum product is "<<maxl<<"."<<endl;
cout<<endl;
}
return 0;
}
C
当两个分数一样是 到达一个临界点
然后 一个变大 一个变小
我们只需要枚举变大的那一个
所以只需要从2*n 枚举到n+1即可
#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
//2147483647
using namespace std;
typedef long long ll;
typedef pair<double, double> PII;
ll n,m,k;
ll cnt=0,sum=0;
ll ans=0;
ll mod=1e9+7;
const int maxn=1e6+199;
ll x,y;char a[100];
ll gcd(int x,int y){
if(x%y==0)
return y;
return gcd(y,x%y);
}
int main(){
map<int,int>mp;
int n;
while(cin>>n){
mp.clear();
cnt=0;
for(int i=n*2;i>n;i--){
if(n*i%(i-n)==0)
cnt++;
}
cout<<cnt<<endl;
for(int i=n+1;i<=2*n;i++){
if(n*i%(i-n)==0)
printf("1/%d = 1/%d + 1/%d\n",n,n*i/(i-n),i);
}
}
return 0;
}
D
素数环 相邻两个数的和是素数
采取回溯法写即可 在新位置上填数 然后判断进行下一步
然后写一个终止条件
#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
//2147483647
using namespace std;
typedef long long ll;
typedef pair<double, double> PII;
ll n,m,k;
ll cnt=0,sum=0;
ll ans=0;
ll mod=1e9+7;
const int maxn=1e6+199;
ll x,y;
int pre[200];
int bj[200];
int a[100];
int vis[200];
ll smp(){
for(int i=2;i<=100;i++){
if(!bj[i])
pre[cnt++]=i;
for(int j=0;j<cnt&&pre[j]*i<=200;j++){
bj[pre[j]*i]=1;
if(i%pre[j]==0) break;
}
}
}
void dfs(int tot){
if(tot==n&&!bj[a[0]+a[n-1]]){
cout<<a[0];
for(int i=1;i<n;i++) cout<<" "<<a[i];
cout<<endl;
}
else{
for(int i=2;i<=n;i++){
if(!bj[i+a[tot-1]]&&!vis[i])
{
a[tot]=i;
vis[i]=1;
dfs(tot+1);
vis[i]=0;
}
}
}
}
int main(){
smp();
while(cin>>n){
a[0]=1;
cout<<"Case "<<++ans<<":"<<endl;
dfs(1);
putchar('\n');
}
return 0;
}
E
令当前游标为tot,假设cur以前的字符串是困难的串(dfs已经判断过),那么只用考虑当前插入tot处的字符和之前的串是否满足困难串的条件;这样就是以tot为基准点依次向前对称匹配,从一个字符到(tot+1)/2个字符的匹配。
#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
//2147483647
using namespace std;
typedef long long ll;
typedef pair<double, double> PII;
ll n,m,k;
ll cnt=0,sum=0;
ll mod=1e9+7;
const int maxn=1e6+199;
ll l,r;
map<int,int>mp;
priority_queue<int , vector<int>,greater<int> >q;bool number[maxn];
int h=0;
ll s[maxn];
void print(int tot){
int i;
for(i=0;i<tot;i++)
{
if(i!=0&&i%4==0)
if(i!=0&&i%64==0)
printf("\n");
else
printf(" ");
printf("%c",'A'+s[i]);
}
printf("\n%d\n",tot);
}
int dfs(int tot){
if(cnt++==n) {
print(tot);
return 0;
}
for(int i=0;i<m;i++){ //将第tot位进行填补
s[tot]=i;
int ok=1;
for(int j=1;j<=(tot+1)/2;j++){ //判断是否有重复子串
int flag=1;
for(int len=0;len<j;len++){
if(s[tot-len]!=s[tot-j-len]) {
flag=0;
break;
}
}
if(flag){
ok=0;
break;
}
}
if(ok){
if(!dfs(tot+1)) return 0;
}
}
return 1;
}
int main(){
while(cin>>n>>m&&n&&m){
memset(s,0,sizeof(s));
cnt=0;
dfs(0);
}
return 0;
}
F
这是一个图,输入给出的是某个节点。冒号后面的是和这个节点相邻的节点有哪些 分号代表一个描述结束;
每一种排法中,相邻点距离最大的,作为这种排法的带宽。 问哪种排法带宽最小;
求最小宽度 用全排列即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+100;
vector<int> v[26];
bool ch[26];
int ans[10],id[10];
int main(){
string line;
while(cin>>line && line[0]!='#'){
for(int i=0;i<26;i++) v[i].clear();
memset(ch,0,sizeof(ch));
for(int i=0,j,len=line.length();i<len;i++){
ch[line[i]-'A']=true;
for(j=i+2;j<len && line[j]!=';';j++){
v[line[i]-'A'].push_back(line[j]-'A');
ch[line[j]-'A']=true;
}
i=j;
}
int n=0;
for(int i=0;i<26;i++) if(ch[i]) id[n++]=i;
int res=n;
do{
int maxn=0;
for(int i=0;i<n;i++){
for(int j=0,len=v[id[i]].size();j<len;j++){
for(int k=0;k<n;k++){
if(id[k]==v[id[i]][j]) {
maxn=max(maxn,abs(k-i));
break;
}
}
if(maxn>=res) break;
}
if(maxn>=res) break;
}
if(res>maxn){
memcpy(ans,id,sizeof(id));
res=maxn;
}
}while(next_permutation(id,id+n));
for(int i=0;i<n;i++)
cout<<char(ans[i]+'A')<<" ";
cout<<"-> "<<res<<endl;
}
return 0;
}
J
迭代加深法
题目大意:将一个数字序列以最少的剪切次数粘贴成另一个数字序列。
剪枝策略判断:当前估价函数值+当前深度>预先最大搜索深度 然后剪枝
剪枝最多改变三个数字位置的正确性
每次搜索前h>(maxd-d)*3时剪枝 (maxd-d)是剩余搜索次数
/*
*/
#include<bitsdc++.h>
using namespace std;
const int maxn = 9;
int n, a[maxn];
bool is_finish() {
for(int i = 0; i < n-1; i++)
if(a[i] >= a[i+1]) return false;
return true;
}// 判断是否到达目标状态
int h() {
int cnt = 0;
for(int i = 0; i <n-1; i++)
if(a[i]+1 != a[i+1]) cnt++;
if(a[n-1] != n) cnt++;
return cnt;
} //统计需要变更的总数
bool dfs(int d, int maxd) {
if(d*3 + h() > maxd*3) return false; //估价函数
if(is_finish()) return true; //边界条件
int b[maxn], former[maxn];
memcpy(former, a, sizeof(a)); //存放原图
for(int i = 0; i < n; i++)
for(int j = i; j < n; j++) {
int cnt = 0;
for(int k = 0; k < n; k++)
if(k < i || k > j) b[cnt++] = a[k];
for(int k = 0; k <= cnt; k++) {
int cnt2 = 0;
for(int p = 0; p < k; p++) a[cnt2++] = b[p]; //插入已经拍好序的
for(int p = i; p <= j; p++) a[cnt2++] = former[p]; //插入
for(int p = k; p < cnt; p++) a[cnt2++] = b[p]; //插入终止状态
if(dfs(d+1, maxd)) return true;
memcpy(a,former, sizeof(a));
}
}
return false;
}
int solve() {
if(is_finish()) return 0;
int ans = 8;
for(int maxd = 1; maxd <ans; maxd++)
if(dfs(0, maxd)) return maxd;
return ans;
}
int main() {
int kass= 0;
while(cin>>n&&n) {
for(int i = 0; i < n; i++) scanf("%d", &a[i]);
printf("Case %d: %d\n", ++kass, solve());
}
return 0;
}
H
T组测试数据,每组测试数据输入4个整数,分别表示第一个杯子的容量、第二个杯子的容量、第三个杯子的量、目标容量,4个整数(小于200大于0)。输出最小的总倒水量和目标容量,如果倒不出目标容量,就 输出能倒出的小于目标容量的最大的容量的总倒水量和容量。
a->b a->c b->a b->c c->a c->b 有这几种情况
桶是没有刻度的 只有容量大小
我们优先提取出 倒水过程中用量最少的 因为这样是最优的
#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
//2147483647
using namespace std;
typedef long long ll;
typedef pair<double, double> PII;
ll n,m,k;
ll cnt=0,sum=0;
ll mod=1e9+7;
const int maxn=1e6+199;
ll x,y;
int cap[3];
int vis[250][250];
int ans[250];
struct Node{
int v[3];
int dis;
bool operator <(const Node& res) const{
return res.dis<dis;
}
}f,t;
void __init__(const Node & u){
for(int i=0;i<3;i++){
int k=u.v[i];
if(ans[k]<0||ans[k]>u.dis) ans[k]=u.dis;
}
}
void bfs(int a,int b,int c,int d){
memset(vis,0,sizeof(vis));
memset(cap,0,sizeof(cap));
memset(ans,-1,sizeof(ans));
cap[0]=a;cap[1]=b;cap[2]=c; //桶的容量
priority_queue<Node>q;
f.v[0]=0;
f.v[1]=0;
f.v[2]=c;
f.dis=0;
vis[0][0]=1;
q.push(f);
while(q.size()){
f=q.top(); //提取出dis最小的 dis代表 倒水使用量
q.pop();
__init__(f);
if(ans[d]>=0) break; //如果这个水量已经达到 直接break;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
if(i==j) continue;
if(f.v[i]==0||f.v[j]==cap[j]) continue;
int tmp=min(cap[j],f.v[i]+f.v[j])-f.v[j]; //tmp 代表j桶可以接收多少体积
t=f;
t.v[i]=f.v[i]-tmp;
t.v[j]=f.v[j]+tmp;
t.dis=f.dis+tmp;
if(!vis[t.v[0]][t.v[1]]) //如果这个状态未曾有过 入队
{
vis[t.v[0]][t.v[1]]=1;
q.push(t);
}
}
}
}
while(d>=0){
if(ans[d]>=0) {
printf("%d %d\n",ans[d],d);
return;
}
d--;
}
}
int main(){
cin>>n;
while(n--){
int a,b,c,d;
cin>>a>>b>>c>>d;
bfs(a,b,c,d);
}
}
K
两个宝石 体积价值分别为 s1 v1 、s2 v2
给我们一个背包容量 宝石数量无限
如何取得最大价值
可能会是背包 但是数据太大
如果背包容量不是很大的话 比如 n/s1 <1e6 我们可以边跑边判断取得最大价值
如果容量太大 T了 就要换一种思路 如果拿s2件v1 他的价值就是s2v1 体积是s2v1
同样的拿s1件v2 他的价值为 s1v2 体积是s1s2
我们可以看到 他们的体积一样 都是s1s2 然后我么可以比较他们的价值
如果s2v1更大的话 说明 每一个s2v1体积 我都可以装v1这个宝石 因为这个体积下 v1的价值更大
然后不足s1s2的体积 我们可以暴力跑 判断装v2是否有最大价值
#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
//2147483647
using namespace std;
typedef long long ll;
typedef pair<double, double> PII;
ll n,m,k;
ll cnt=0,sum=0;
ll mod=1e9+7;
const int maxn=1e6+199;
ll x,y;
int main()
{
cin>>m;
while(m--){
ll s1,v1,s2,v2;
cin>>n>>s1>>v1>>s2>>v2;
ll maxl=-1;
if(n/s1<1e6){
for(ll i=0;i<=n/s1;i++){
sum=i*v1;
sum+=(n-i*s1)/s2*v2;
maxl=max(sum,maxl);
}
}else if(n/s2<1e6){
for(ll i=0;i<=n/s2;i++){
sum=i*v2;
sum+=(n-i*s2)/s1*v1;
maxl=max(sum,maxl);
}
}else{
if(s2*v1<s1*v2){
for(ll i=0;i<=s2;i++){
sum=i*v1;
sum+=(n-i*s1)/s2*v2;
maxl=max(sum,maxl);
}
}else{
for(ll i=0;i<=s1;i++){
sum=i*v2;
sum+=(n-i*s2)/s1*v1;
maxl=max(sum,maxl);
}
}
}
cout<<"Case #"<<++cnt<<": ";
cout<<maxl<<endl;
}
return 0;
}
L
也是一个小小的dfs啊 可以利用计算后的结果 只能进行乘除运算
对于幂来说就是加减运算
我们把每一次计算的结果保存下来
然后然后然后利用就好
#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
//2147483647
using namespace std;
typedef long long ll;
typedef pair<double, double> PII;
ll n,m,k;
ll cnt=0,sum=0;
ll mod=1e9+7;
const int maxn=1e6+199;
ll l,r;
map<int,int>mp;
priority_queue<int , vector<int>,greater<int> >q;
bool number[maxn];
ll prime[maxn];
int h=0;
int a[maxn];
bool dfs(int x,int d){
if(d>h) return 0;
if(x==n) return 1;
if(x<<(h-d)<n) return 0;
a[d]=x;
for(int i=0;i<=d;i++){
if(dfs(a[i]+x,d+1)) return 1;
if(dfs(abs(a[i]-x),d+1)) return 1;
}
return 0;
}
int main(){
while(cin>>n&&n){
h=0;
while(!dfs(1,0)) h++;
cout<<h<<endl;
}
return 0;
}