暴力n^2可过,不过有个n的解法。
//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//LOOP
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FD(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
#define CPY(a, b) memcpy(a, b, sizeof(a))
#define FC(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)
typedef long long LL;
const int INF = 1000000007;
const double eps = 1e-10;
const int maxn = 5010;
int a[maxn];
map<int, int>M;
int n, p;
int main ()
{
int x, y;
while (~RII(n, p))
{
M.clear();
for (int i = 1; i <= n; i++) RI(a[i]);
int ans = 0, ansx;
for (int i = 1; i <= n; i++)
{
int x = a[i] - (i - 1) * p;
if (x >= 1)
{
M[x]++;
if (ans < M[x])
{
ans = M[x];
ansx = x;
}
}
}
cout << n - ans << endl;
int x = ansx;
for (int i = 1; i <= n; i++)
{
int y = x - a[i];
if (y > 0) printf("+ %d %d\n", i, y);
else if (y < 0) printf("- %d %d\n", i, -y);
x += p;
}
}
return 0;
}
C. Searching for Graph
构造题。n个点要求2*n+p条边,且其有k点的子图不能超过2*k+p条边
关键是想到。每个点的度要>=2。(这种条件是不不完整的)正确的应该是,每个点至少对应不和其它点公用的不同的2条边。
或者先每个点按序构造两条边,再添加。其实直接按照1到n的顺序构造,也可保证正确。
注意:不能有重边和子环。
//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//LOOP
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FD(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
#define CPY(a, b) memcpy(a, b, sizeof(a))
#define FC(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)
typedef long long LL;
const int INF = 1000000007;
const double eps = 1e-10;
const int MAXN = 1000010;
int main ()
{
int n, p;
int T;
RI(T);
while(T--)
{
RII(n, p);
int x = p / n;
int y = p % n;
for (int i = 0; i < n; i++)
{
int up = i + x + 2;
if (y) up++, y--;
if (up >= n)
{
for (int j = i + 1; j < n; j++)
printf("%d %d\n", i + 1, j + 1);
for (int j = 0; j <= up % n; j++)
printf("%d %d\n", i + 1, j + 1);
}
else
{
for (int j = i + 1; j <= up; j++)
printf("%d %d\n", i + 1, j + 1);
}
}
}
return 0;
}
D. Upgrading Array
题目有下2种做法,其实实质是相同的。
第1个解法的效率高些,但第二个解法写起来更加的简单。第一种解法,其实是对每个前缀序列的最大gcd进行了,细节分析,确定操作后对解的影响值记为get(gcd);其实没必要这么做,
从第2个解法可以看出,只要知道要处理的前缀序列的最大gcd,就可一比较简单的计算出操作后对解的影响get(gcd)。
再对序列进行操作时,倒着操作可保证最优:
因为操作的区间是[1, r],且操作区间每个数除以[1,r]的区间求最大gcd。
大区间的gcd值受小区间的影响,且小区间处理后,大区间就没有办法处理,所以如果有多个操作,则一定是按照大区间到小区间的操作顺序。
具体处理:对每个[1,r]的区间求最大gcd,保存在gc[]中,则gc[i - i] >= gc[i],且实际上gc[i]是gc[i - 1]的因子。
(1)如果get(gc[i])> 0;则不应当对其操作,倒着处理时,对区间[1,i]不操作。对于区间[1, i - 1]的操作与否,再进行判断。
(2)如果get(gc[i])<0;则应当对其操作,倒着处理时,对区间[1,i]不操作。
自己的解法:
//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//LOOP
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FD(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
#define CPY(a, b) memcpy(a, b, sizeof(a))
#define FC(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)
typedef long long LL;
const int INF = 1000000007;
const double eps = 1e-10;
const int maxn = 5010;
vector<int>t, a, b, c;
int ans;
set<int>S;
int n, m;
void get_sum()
{
for (int r = 0; r < a.size(); r++)
{
int x = a[r];
for (int i = 2; i * i <= x; i++)
{
while (x % i == 0)
{
x /= i;
if (S.find(i) == S.end()) ans++;
else ans--;
}
}
if (x != 1)
{
if (S.find(x) == S.end()) ans++;
else ans--;
}
}
return ;
}
void get_t(vector<int> b, int val)
{
for (int r = 0; r < b.size(); r++)
{
int x = b[r], num = 0, nownum;
int y = a[0];
while (y % x == 0)
{
y /= x;
num++;
}
if(!num) continue;
for (int i = 1; i < a.size(); i++)
{
y = a[i];
nownum = 0;
while (y % x == 0)
{
nownum++;
y /= x;
}
nownum = min(nownum, num);
if (nownum < num)
{
t[i - 1] += val * (num - nownum);
num = nownum;
}
}
t[a.size() - 1] += val * num;///!!!
}
}
void solve()
{
for (int r = n - 1; r >= 0; r--)
{
if (t[r] < 0)
ans -= (r + 1) * t[r];
else if (r)///!!!!
t[r - 1] += t[r];
}
}
int main ()
{
int x, y;
S.clear();
ans = 0;
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
RI(x);
a.push_back(x);
t.push_back(0);
}
for (int i = 1; i <= m; i++)
{
RI(x);
b.push_back(x);
S.insert(x);
}
x = a[0];
for (int i = 2; i * i <= x; i++)
{
if (x % i == 0)
{
if (S.find(i) == S.end())
c.push_back(i);
while (x % i == 0)
x /= i;
}
}
if (x != 1 && S.find(x) == S.end()) c.push_back(x);
get_sum();
get_t(b, -1);
get_t(c, 1);
solve();
cout << ans << endl;
return 0;
}
参考他人的做法:
//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)
typedef long long LL;
const int INF = 1000000007;
const double eps = 1e-10;
const int maxn = 5010;
int gc[maxn], a[maxn];
set<int>S;
int n, m;
int get(int x)
{
int ret = 0;
for (int i = 2; i * i <= x; i++)
{
while (x % i == 0)
{
x /= i;
if (S.find(i) == S.end()) ret++;
else ret--;
}
}
if (x > 1)
{
if (S.find(x) == S.end()) ret++;
else ret--;
}
return ret;
}
int solve()
{
int ans = 0;
for (int i = 1; i <= n; i++)
ans += get(a[i]);
int com_gcd = 1;
for (int i = n; i >= 1; i--)
{
int z = get(gc[i] / com_gcd);
if (z < 0)
{
ans -= z * i;
com_gcd *= (gc[i] / com_gcd);
}
}
return ans;
}
int main ()
{
int x, y;
S.clear();
cin >> n >> m;
for (int i = 1; i <= n; i++)
RI(a[i]);
for (int i = 1; i <= m; i++)
{
RI(x); S.insert(x);
}
gc[1] = a[1];
for (int i = 2; i <= n; i++) gc[i] = __gcd(gc[i - 1], a[i]);
cout << solve() << endl;
return 0;
}
E. Strictly Positive Matrix
...