D
题意:
给你一个长度2e5的字符串,由数字组成,问你有多少个子串能被2019整除。
思路:
跟这道题一样:基本一样的题,ABC round 158的E题,这种求子串满足整除某个数p的问题,基本套路就是维护一个从结尾到首的数模p的值,然后扫完一遍,就从模下来每个可能的值随意取两个,因为这相同的两个模数的位置之间的那个数字串肯定是能整除p的,注意如果模p是2和5就要特别讨论一下,因为他们是10的因数,也就是158E题要考虑的。
#include <bits/stdc++.h>
#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
#define SZ(x) ((int)(x).size())
using namespace std;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }
const int mod = 2019;
const int maxn = 200000+100;
i64 pref[maxn], cnt[maxn];
string s;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.precision(10);
cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
ms(cnt, 0);
cin >> s;
int len = SZ(s);
int ten = 1, now = 0;
for (int i = len-1; i >= 0; --i) {
int num = int(s[i] - '0');
now = (ten*num+now)%mod;
pref[i] = now;
++cnt[now];
ten = (ten*10)%mod;
}
i64 ans = 0;
++cnt[0];
for (int i = 0; i < 2019; ++i) {
if (cnt[i] >= 2) {
ans += cnt[i]*(cnt[i]-1)/2;
}
}
cout << ans << '\n';
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
E
题意:
有n个点(<=50),编号为1到n,m条边(<=100), 你开局在1号点,有10^100的金币和s(0 <= s <=1e9)个银币,每个点都有两个属性c(1 <= c <= 1e9)和d(1 <= d <= 1e9),表示每d秒钟可以将你的1个金币换为c个银币,m条边 u, v, a, b,表示u和v之间有条双向边,消耗a(1 <= a <= 1e9)个银币和b(1 <= b <= 1e9)秒经过。现在问你从1号点分别到2 ~ n号点的最短耗时。
思路:
首先假设有50个点,每条边都要50个银币,而且c等于1,走完所有点需要49条边,那么最多需要的金币是49*50 = 2450,所以金币肯定是远远够用的, 我设最多需要3000就够,先把s和3000取个min,至于为什么,下面要开dp数组,s取值是可以到1e9的,会runtime error。
先搞了dp数组,dp[i][j]表示第i个点有j个银币的最小耗时,j我开了3000大小,比2450大就行。
现在就跑一边dijkstra就行,每个点有两个属性,当前在哪个点和目前的耗时,pop出来的每个点都要枚举一下如果在此处换金币的情况,用dp维护要不要更新,松弛操作里就是维护从当前过去的状态看看要不要更新,如果要更新的话就push进去。
现在来看时间复杂度:
最坏情况,假设每个dp[50][3000]每个情况都有,那么优先队列的时间复杂度就是50*3000*log(50*3000)大概是1e6,每次还要跑100条边,复杂度就是1e8,给了2s,应该能过,应为不可能每次都跑100条边的,1e8肯定跑不满。
我觉得自己讲的也听模糊的,看代码吧。
#include <bits/stdc++.h>
#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
#define SZ(x) ((int)(x).size())
using namespace std;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }
const int maxn = 110; //点数
const i64 INF = 0x3f3f3f3f3f3f3f3fLL;
struct node {
int id, w, money; // w == distance
node(){}
node(int a, int b, int c) : id(a), w(b), money(c) {}
friend bool operator < (node a, node b) {return a.w > b.w;}
};
vector<node> G[maxn];
i64 dp[55][3050], a[maxn], b[maxn], c[maxn], d[maxn];
i64 n, m, s;
void dij(int start, int n) {
for (int i = 0; i <= 50; ++i) {
for (int j = 0; j <= 3000; ++j) {
dp[i][j] = INF;
}
}
priority_queue<node> q;
node cur;
q.push(node(start, 0, s));
dp[start][s] = 0;
while (!q.empty()) {
cur = q.top();
q.pop();
int u = cur.id;
int temp = cur.money+c[u];
temp = min(temp, 3000);
if (dp[u][temp] > dp[u][cur.money]+d[u]) {
dp[u][temp] = dp[u][cur.money]+d[u];
q.push(node(u, dp[u][temp], temp));
}
for (node to : G[cur.id]) {
if (cur.money >= to.money
&& dp[to.id][cur.money-to.money] > dp[cur.id][cur.money]+to.w) {
dp[to.id][cur.money-to.money] = dp[cur.id][cur.money]+to.w;
q.push(node(to.id, dp[to.id][cur.money-to.money], cur.money-to.money));
}
}
}
}
void init(int n) {
for (int i = 0; i <= n; ++i) G[i].clear();
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.precision(10);
cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin >> n >> m >> s;
s = min(s, 3000LL);
init(n);
forn(i, m) {
int u, v;
cin >> u >> v >> a[i] >> b[i];
G[u].eb(node(v, b[i], a[i]));
G[v].eb(node(u, b[i], a[i]));
}
for1(i, n) cin >> c[i] >> d[i];
dij(1, n);
for (int i = 2; i <= n; ++i) {
i64 ans = LLONG_MAX;
for (int j = 0; j <= 3000; ++j) {
ans = min(ans, dp[i][j]);
}
cout << ans << '\n';
}
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}