2020 Multi-University Training Contest 2(1005,1006,1010,1012题解)

1006 : T h e O c u l u s \color{Red}1006:The Oculus 1006:TheOculus

算 法 : 取 模 + 暴 力 算法:取模+暴力 :+

虽 然 a , b , c 非 常 的 大 , 但 是 我 们 可 以 直 接 暴 力 取 模 虽然a,b,c非常的大,但是我们可以直接暴力取模 a,b,c,

模 数 你 任 意 定 , 暴 力 预 处 理 取 模 后 的 斐 波 那 契 数 列 模数你任意定,暴力预处理取模后的斐波那契数列 ,

再 暴 力 计 算 a , b , c , 一 项 一 项 加 上 对 应 的 斐 波 那 契 并 取 模 再暴力计算a,b,c,一项一项加上对应的斐波那契并取模 a,b,c,

然 后 枚 举 c 的 每 一 位 为 0 的 位 置 , 试 着 改 成 1 , 看 看 能 否 实 现 a ∗ b = = c 然后枚举c的每一位为0的位置,试着改成1,看看能否实现a*b==c c0,1,ab==c

原 理 : 上 面 的 操 作 只 涉 及 加 法 和 乘 法 \color{Red}原理:上面的操作只涉及加法和乘法 :

所 以 取 模 不 会 改 变 彼 此 的 关 系 所以取模不会改变彼此的关系

但 是 这 里 用 了 双 模 数 判 断 , 为 了 保 险 一 点 但是这里用了双模数判断,为了保险一点 ,

/*
  Author : lifehappy
*/
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include 
#define mp make_pair
#define pb push_back
#define endl '\n'

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair pii;

const double pi = acos(-1.0);
const double eps = 1e-7;
const int inf = 0x3f3f3f3f;

inline ll read() {
    ll f = 1, x = 0;
    char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }
    return f * x;
}
const int N = 2e6 + 10;
const int mod1 = 1e9 + 7, mod2 = 1e9 + 9;
int a[N], b[N];
int x[N];
int main() {
    a[1] = b[1] = 1, a[2] = b[2] = 2;
    for(int i = 3; i < N; i++) {
        a[i] = (a[i - 1] + a[i - 2]) % mod1;
        b[i] = (b[i - 1] + b[i - 2]) % mod2;
    }
    int t = read();
    while(t--) {
        ll a1 = 0, a2 = 0, b1 = 0, b2 = 0, c1 = 0, c2 = 0;
        int n = read();
        for(int i = 1; i <= n; i++) {
            int x = read();
            if(x) {
                a1 = (a1 + a[i]) % mod1;
                a2 = (a2 + b[i]) % mod2;
            }
        }
        int m = read();
        for(int i = 1; i <= m; i++) {
            int x = read();
            if(x) {
                b1 = (b1 + a[i]) % mod1;
                b2 = (b2 + b[i]) % mod2;
            }
        }
        int k = read();
        for(int i = 1; i <= k; i++) {
            x[i] = read();
            if(x[i]) {
                c1 = (c1 + a[i]) % mod1;
                c2 = (c2 + b[i]) % mod2;
            }
        }
        ll mult1 = (a1 * b1) % mod1, mult2 = (a2 * b2) % mod2;
        int ans;
        for(int i = 1; i <= k; i++) {
            if(x[i]) continue;
            if((c1 + a[i]) % mod1 == mult1 && (c2 + b[i]) % mod2 == mult2) {
                ans = i;
                break;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}


1010 : L e a d o f W i s d o m \color{Red}1010:Lead of Wisdom 1010:LeadofWisdom

算 法 : 搜 索 算法:搜索 :

比 较 容 易 想 到 的 是 折 半 搜 索 比较容易想到的是折半搜索

按 照 每 类 物 品 的 数 量 进 行 排 序 , 然 后 均 分 到 两 个 集 合 中 ( 保 证 物 品 均 匀 分 配 ) 按照每类物品的数量进行排序,然后均分到两个集合中(保证物品均匀分配) ,()

在 两 个 集 合 中 d f s 出 所 有 可 能 的 a , b , c , d 组 合 在两个集合中dfs出所有可能的a,b,c,d组合 dfsa,b,c,d

暴 力 枚 举 两 个 集 合 搜 出 的 a , b , c , d 组 合 , 计 算 答 案 暴力枚举两个集合搜出的a,b,c,d组合,计算答案 a,b,c,d,

#include 
using namespace std;
#define int long long
struct p{
	int ok,a,b,c,d;
}w[100009];
vector

vec[59],svec[59],q,r; int n,k,shu[52],id[52],ans,top1,top2; bool com(int a,int b){ return shu[a]>shu[b]; } void dfs(int pos,int a,int b,int c,int d) { if( pos==k+1 ) { q.push_back((p){0,a,b,c,d}); return; } for(int i=0;i> t; while( t-- ) { q.clear(); r.clear(); cin >> n >> k; ans=0; for(int i=1;i<=50;i++) id[i]=i; for(int i=0;i<=50;i++) vec[i].clear(),svec[i].clear(); for(int i=1;i<=n;i++) { cin >> w[i].ok >> w[i].a >> w[i].b >> w[i].c >> w[i].d; shu[ok]++;//记录每类物品的数量 } sort(id+1,id+1+k,com);//按照数量排序 for(int i=1;i<=k;i++) { int sd=id[i]; if( i%2==1 )//给vec { for(int j=1;j<=n;j++) if( w[j].ok==sd ) vec[ w[j].ok ].push_back(w[j]); } else//给svec { for(int j=1;j<=n;j++) if( w[j].ok==sd ) svec[ w[j].ok ].push_back(w[j]); } } dfs(1,0,0,0,0); dfs1(1,0,0,0,0); for(int i=0;i


1012 : S t r i n g D i s t a n c e \color{Red}1012:String Distance 1012:StringDistance

算 法 : 序 列 自 动 机 + d p 算法:序列自动机+dp :+dp

由 序 列 自 动 机 预 处 理 n x t [ i ] [ j ] 由序列自动机预处理nxt[i][j] nxt[i][j]

表 示 a 串 在 i 位 置 后 最 快 出 现 的 j 字 母 在 哪 一 个 位 置 表示a串在i位置后最快出现的j字母在哪一个位置 aij

令 d p [ i ] [ j ] 为 a 串 从 i 位 置 开 始 和 b 匹 配 , 匹 配 了 j 个 字 母 的 最 小 结 束 位 置 令dp[i][j]为a串从i位置开始和b匹配,匹配了j个字母的最小结束位置 dp[i][j]aib,j

那么转移方程的伪代码是

for(int i=1;i<=m;i++)//枚举匹配了b串的i个字母
for(int j=i;j<=m;j++)//枚举匹配i个字母时的结尾字母
for(int q=i-1;q<=j;q++)//枚举匹配i-1个字母时的结尾字母
{
	int last=dp[i-1][q];//上一个字母在last位置完成匹配
	int kk=nxt[last][ b[j]-'a' ];//那么在last后b[j]最快出现的位置在这里
	dp[i][j]=min(dp[i][j],kk);
}

A C 代 码 AC代码 AC

#include 
using namespace std;
int dp[22][22],nxt[100009][27],ans[100009][22];
char a[100009],b[100009];
void make_nxt(int nxt[][27],int len,char a[])//构造nxt数组 
{
	for(int i=0;i<=25;i++)	nxt[len][i]=1e9;
	for(int i=len-1;i>=0;i--)
	{
		for(int j=0;j<=25;j++)	nxt[i][j]=nxt[i+1][j];
		nxt[i][a[i+1]-'a']=i+1;//一次只会更新a[i+1]-'a'的值 
	}
}
int main()
{
	int t;
	cin >> t;
	while( t-- )
	{
		cin >> (a+1) >> (b+1);
		int m=strlen(b+1),n=strlen(a+1);
		make_nxt(nxt,n,a);
		for(int i=0;i<=n;i++)
		for(int j=0;j<=m;j++)
			ans[i][j]=1e9;//以i开头匹配j个字母的最小结束位置 
		for(int i=1;i<=n;i++)
		{
			//匹配j个字母,以q结尾 
			memset(dp,0x7f,sizeof(dp));
			int df=dp[0][0];
			for(int q=1;q<=m;q++)//预处理匹配一个字母的情况 
			{
				int last=nxt[i-1][ b[q]-'a' ];
				if( last==1e9 )	continue;
				dp[1][q]=last;
				ans[i][1]=min(ans[i][1],last);
			}
			for(int j=2;j<=m;j++)
			for(int q=j;q<=m;q++)//匹配j个以q结尾 
			{
				for(int w=j-1;w> c;
		for(int i=1,l,r;i<=c;i++)
		{
			scanf("%d%d",&l,&r);
			int pipei=0;
			for(int j=m;j>=1;j--)
			{
				if( ans[l][j]<=r )
				{
					pipei=j;
					break;
				}
			}
			printf("%d\n",m+(r-l+1)-2*pipei);
		}
	}
}

1005 : N e w E q u i p m e n t s \color{Red}1005:New Equipments 1005:NewEquipments

本题纯属自己yy,非常可能是假算法

算 法 : 最 小 费 用 最 大 流 算法:最小费用最大流 :

注 意 : 一 下 只 是 口 头 A C , 所 以 只 介 绍 思 想 没 有 代 码 注意:一下只是口头AC,所以只介绍思想没有代码 :AC,

观 察 到 对 于 每 一 个 人 来 说 , 花 费 是 形 如 a i j 2 + b i j + c i 的 二 次 函 数 观察到对于每一个人来说,花费是形如a_ij^2+b_ij+c_i的二次函数 ,aij2+bij+ci

由 于 a i > 0 , 所 以 二 次 函 数 开 口 向 上 由于a_i>0,所以二次函数开口向上 ai>0,

当 机 器 号 j 取 − b 2 a 时 函 数 值 最 小 当机器号j取\frac{-b}{2a}时函数值最小 j2ab

所 以 在 这 个 点 附 近 的 n 个 点 都 可 能 作 为 机 器 被 选 所以在这个点附近的n个点都可能作为机器被选 n

为 什 么 不 直 接 选 这 个 对 称 轴 ? 因 为 让 给 别 人 选 可 能 更 优 为什么不直接选这个对称轴?因为让给别人选可能更优 ?

所 以 类 似 二 分 图 匹 配 所以类似二分图匹配

源 点 向 n 个 人 连 边 权 为 1 的 点 , 选 出 来 的 所 有 机 器 点 向 汇 点 连 边 权 1 的 边 源点向n个人连边权为1的点,选出来的所有机器点向汇点连边权1的边 n1,1

每 个 人 向 每 台 被 选 出 来 的 机 器 连 一 条 边 ( 因 为 每 个 人 都 可 以 用 任 意 的 机 器 ) , 边 权 无 穷 每个人向每台被选出来的机器连一条边(因为每个人都可以用任意的机器),边权无穷 (),

跑 最 小 费 用 最 大 流 跑最小费用最大流

代码没有,因为没时间啦!!

你可能感兴趣的:(div题解)