排序不等式(Rearrangement Inequality)

排序不等式

题一

题一

#include <iostream>
#include <algorithm>
using LL = long long;
const int N = 100010;
LL times[N];
int n;

int main()
{
    std::cin>>n;
  
    LL sum = 0;
    for(int i = 1;i<=n;i++) scanf("%d", &times[i]);
    std::sort(times+1,times+n+1);
    for(int i = 1;i<=n;i++) {
        sum += times[i]*(n-i);
    }
    std::cout<<sum;
}

题二

Question2

此题来源于杭电多校第四场,根据题意注意 $0229$ 也是合法的。

题解:首先记录每一个字符出现过的下标值,然后根据题意,分别对 $名字$ 部分从前到后进行字典序最小的二分匹配,对 $生日$ 部分从后到前进行字典序最大的二分匹配,最后根据 $名字$ 部分的尾字符地址和 $生日$ 部分的首字符地址进行计值即可。

#pragma GCC optimize(2)
#include <iostream>
#include <map>
#include <cstring>
#include <vector>
#include <algorithm>
#include <string>
using ll = long long;
std::map <char, std::vector<int>> C_index;
std::string strN, strS;
//嘿,来打表哥们
std::string dates[] = {
	"0101","0102","0103","0104","0105",
	"0106","0107","0108","0109","0110",
	"0111","0112","0113","0114","0115",
	"0116","0117","0118","0119","0120",
	"0121","0122","0123","0124","0125",
	"0126","0127","0128","0129","0130",
	"0131","0201","0202","0203","0204",
	"0205","0206","0207","0208","0209",
	"0210","0211","0212","0213","0214",
	"0215","0216","0217","0218","0219",
	"0220","0221","0222","0223","0224",
	"0225","0226","0227","0228","0229",
	"0301","0302","0303","0304","0305",
	"0306","0307","0308","0309","0310",
	"0311","0312","0313","0314","0315",
	"0316","0317","0318","0319","0320",
	"0321","0322","0323","0324","0325",
	"0326","0327","0328","0329","0330",
	"0331","0401","0402","0403","0404",
	"0405","0406","0407","0408","0409",
	"0410","0411","0412","0413","0414",
	"0415","0416","0417","0418","0419",
	"0420","0421","0422","0423","0424",
	"0425","0426","0427","0428","0429",
	"0430","0501","0502","0503","0504",
	"0505","0506","0507","0508","0509",
	"0510","0511","0512","0513","0514",
	"0515","0516","0517","0518","0519",
	"0520","0521","0522","0523","0524",
	"0525","0526","0527","0528","0529",
	"0530","0531","0601","0602","0603",
	"0604","0605","0606","0607","0608",
	"0609","0610","0611","0612","0613",
	"0614","0615","0616","0617","0618",
	"0619","0620","0621","0622","0623",
	"0624","0625","0626","0627","0628",
	"0629","0630","0701","0702","0703",
	"0704","0705","0706","0707","0708",
	"0709","0710","0711","0712","0713",
	"0714","0715","0716","0717","0718",
	"0719","0720","0721","0722","0723",
	"0724","0725","0726","0727","0728",
	"0729","0730","0731","0801","0802",
	"0803","0804","0805","0806","0807",
	"0808","0809","0810","0811","0812",
	"0813","0814","0815","0816","0817",
	"0818","0819","0820","0821","0822",
	"0823","0824","0825","0826","0827",
	"0828","0829","0830","0831","0901",
	"0902","0903","0904","0905","0906",
	"0907","0908","0909","0910","0911",
	"0912","0913","0914","0915","0916",
	"0917","0918","0919","0920","0921",
	"0922","0923","0924","0925","0926",
	"0927","0928","0929","0930","1001",
	"1002","1003","1004","1005","1006",
	"1007","1008","1009","1010","1011",
	"1012","1013","1014","1015","1016",
	"1017","1018","1019","1020","1021",
	"1022","1023","1024","1025","1026",
	"1027","1028","1029","1030","1031",
	"1101","1102","1103","1104","1105",
	"1106","1107","1108","1109","1110",
	"1111","1112","1113","1114","1115",
	"1116","1117","1118","1119","1120",
	"1121","1122","1123","1124","1125",
	"1126","1127","1128","1129","1130",
	"1201","1202","1203","1204","1205",
	"1206","1207","1208","1209","1210",
	"1211","1212","1213","1214","1215",
	"1216","1217","1218","1219","1220",
	"1221","1222","1223","1224","1225",
	"1226","1227","1228","1229","1230",
	"1231",
};

int lastIdx[366];
int T;
int n, m;
int main()
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin >> T;
	while(T--)
	{
		memset(lastIdx, -1, sizeof lastIdx);
		ll ans = 0;
		C_index.clear();
		std::cin >> n >> m;
		std::cin >> strS;
		for(int i = 0;i<m;i++)
		{
			C_index[strS[i]].push_back(i);
		}
		//先预处理生日部分
		for(int i = 0;i<366;i++)
		{
			int idx = m; //字符串的结尾后一个数
			int j = 3;
			for(;j>=0;--j)
			{
				auto findit = std::lower_bound(C_index[dates[i][j]].begin(), C_index[dates[i][j]].end(),idx);
			
				if(C_index[dates[i][j]].size() == 0||findit- C_index[dates[i][j]].begin()==0) break;
				idx = *(findit - 1);
				
			}
			if (j == -1)
			{
				lastIdx[i] = idx;
			}
		}
		//排序方便最后二分查找寻找答案
		std::sort(lastIdx, lastIdx + 366);
		//处理名字部分
		for(int i = 0;i<n;i++)
		{
			std::cin >> strN;
			int idx = -1;
			int j = 0;
			for(;j<strN.size();j++)
			{
				auto findit = std::upper_bound(C_index[strN[j]].begin(), C_index[strN[j]].end(), idx);

				if(findit != C_index[strN[j]].end())
				{
					if (idx != *findit)
						idx = *findit;
				}else
				{
					break;
				}
			}
			if(j!=strN.size())
			{
				continue;
			}
			if(m-idx<=3) continue;
			//二分找到名字部分最后一个字符最小能接到哪个生日的首字符后面,从而贪心找出满足的部分
			auto t = std::upper_bound(lastIdx, lastIdx + 366, idx);
			ans += 366 - (t-std::begin(lastIdx));
		}
		std::cout << ans << "\n";
	}
}