比赛时候卡在全场题L,心态很崩,后来其他题目思考不进去了。。。加上一个队友临时有事也没来训练。。。最后4题收尾。。。
补题补题,现在把暂时都切出来的题目放上题解和代码吧~
------------------------------------------------------------------------------------------------------------------
A:题意是只能对第一堆的土进行移动,求花费代价最小。
贪心求解,O(n)复杂度
首先让c[i] = a[i]-b[i],那么显然c[i]>0意味着第i号位置的土比较多,应该从c[i]>0的位置往c[j]<0的位置移动
用一个指针记录最左端c[i]>0的位置,现在应该用最靠左的土填满当前c[i]<0的位置,然后扫描一遍就A了~
代码如下:
#include
#include
#include
using namespace std;
const int maxn = 1e5+10;
int a[maxn],b[maxn],c[maxn];
int n;
typedef long long LL;
inline int Min(int x, int y) {return xy?x:y; }
int main(){
int T;
scanf("%d",&T);
while (T--){
scanf("%d",&n);
for (int i=1; i<=n; i++) scanf("%d",&a[i]);
for (int i=1; i<=n; i++) scanf("%d",&b[i]);
for (int i=1; i<=n; i++) c[i] = a[i] - b[i];
LL ans = 0;
int idx = 1;
for (int i=1; i<=n; i++) if (c[i]<0) {
while (c[i]<0) {
while (idx<=n && c[idx]<=0) idx++;
int t = Min(-c[i],c[idx]);
ans += (LL)t*abs(i-idx);
c[i] += t; c[idx] -= t;
}
}
printf("%lld\n",ans);
}
return 0;
}
B:对于当前节点i,i*F(i) 相当于累加F(i)个i,F(i)是第i个节点有的合约数节点个数。
那么只要把i加到每个合约数节点后再统计即可。
说的有点不清楚,看代码里面的dfs就能懂的~
#include
#include
#include
using namespace std;
typedef long long LL;
const int mod = 1e9+7;
const int maxn = 2e4+10;
vectorg[maxn];
vectorvec[maxn];
bool vis[maxn];
int w[maxn];
int n,p;
LL cnt[maxn];
LL ans;
void init(){
for (int i=1; i<=10000; i++) vis[i] = 1;
for (int i=2; i<=10000; i++) if (vis[i]) {
for (int j=i+i; j<=10000; j+=i) vis[j] = 0;
}
for (int i=2; i<=10000; i++) if (vis[i]==0) {
for (int j=i; j<=10000; j+=i) vec[j].push_back(i);
}
}
void dfs(int u, int fa) {
int v;
for (int i=0; i
C:n<=9,利用STL的next_permutation枚举全排列,然后统计转换次数
可以预处理a[i]转换为b[j]需要的操作次数,简单题
#include
#include
#include
using namespace std;
const int maxn = 20;
const int INF = 1e9;
int a[maxn],b[maxn],p[maxn];
int cost[maxn][maxn];
int n;
int calc(int x, int y) {
if (x == y) return 0;
if (x < y) swap(x,y);
int res = 0;
while (x>y) {
if (x%2 == 0) {
if (x/2>=y) { x>>=1; res++; }
else {res += x-y; return res; }
}
else {
--x;
res++;
}
}
return res;
}
int t[maxn];
int solve(){
memcpy(t,p,sizeof(t));
int res = 0;
for (int i=1; i<=n; i++) {
if (t[i] != i) {
for (int j=i+1; j<=n; j++) if (t[j] == i) {
swap(t[j],t[i]);
break;
}
res++;
}
}
return res;
}
int main(){
int T;
scanf("%d",&T);
while (T--){
scanf("%d",&n);
for (int i=1; i<=n; i++) scanf("%d",&a[i]);
for (int j=1; j<=n; j++) scanf("%d",&b[j]);
for (int i=1; i<=n; i++) p[i] = i;
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++) cost[i][j] = calc(a[i],b[j]);
int ans = INF;
do {
int f = 0;
for (int i=1; i<=n; i++) f += cost[p[i]][i];
f += solve();
if (f
D: 这题个人认为很难,无法证明结论,但写起来就几行代码。。
#include
using namespace std;
int L1,R1,L2,R2,mod;
int main(){
int T;
scanf("%d",&T);
while (T--) {
scanf("%d%d%d%d%d",&L1,&R1,&L2,&R2,&mod);
if (R2-L2+1>=mod) printf("LOSE\n");
else printf("WIN\n");
}
return 0;
}
E:签到题~
#include
#include
F:找规律题,可以发现满足要求的x转换为二进制后,不会有相邻两位都为1
假设当前枚举的二进制长度为x,满足题意的数字个数为f(x),能发现f(x)是斐波那契数列~
代码如下:
#include
#include
using namespace std;
const int maxn = 70;
typedef long long LL;
LL f[maxn],sum[maxn];
LL n;
void init(){
f[0] = f[1] = 1;
for (int i=2; i<=60; i++) f[i] = f[i-1] + f[i-2];
sum[0] = 1;
for (int i=1; i<=60; i++) sum[i] = sum[i-1] + f[i];
}
int main(){
init();
//freopen("in.txt","r",stdin);
int T;
scanf("%d",&T);
while (T--){
scanf("%lld",&n);
LL ans = 0;
bool isfirst = 1;
while (n>0) {
if (isfirst) {
if (n == 1) {
ans = 1LL;
break;
}
int i=0;
while (sum[i]
G:待填坑
H:待填坑
I:签到题,不过不知道为什么官方题解那么说那么多。。。
也不理解为什么要用java或python写大数。。
很显然的,找到最高位奇数,然后修改就可以了。
假设字符串长度为n,最高奇数为在第i位。
1:第i位数字为9,把第i位数字减一,i+1到n位数字全部变为8
2:看第i位之后的数字是否都是4 或出现 若干个4然后接着一个比4小的数字,是的话第i位数字减一,后面i+1到n位全部为8
3:以上两种情况不满足,把第i位数字加一,后面全部变为0
代码如下:
#include
#include
using namespace std;
const int maxn = 100000+10;
char s[maxn];
int n;
int main(){
int T;
scanf("%d",&T);
while (T--){
scanf("%s",s);
n = strlen(s);
int st = 0;
while (st=n) {
printf("%s\n",s);
continue;
}
if (n == 1 && s[0] == '1') {
printf("0\n");
continue;
}
int nxt = st+1;
while (nxt=n || s[nxt]<'4' || s[st]=='9') {
s[st]--;
for (int i=st+1; i
J:二分+二分图最大匹配
最多N+1个空位,m个点向可以插入的空连边。有n+1-m个虚点,向|ai-1 - ai| <= len 的空连边 ,结果要求完全匹配~
代码如下:
#include
#include
#include
using namespace std;
const int INF = 1e9+7;
const int maxn = 200+10;
int n,m;
int a[maxn],b[maxn];
int g[maxn][maxn];
int left[maxn];
bool vis[maxn];
bool match(int u) {
for (int i=1; i<=m; i++) if (g[i][u] && !vis[i]) {
vis[i] = 1;
if (!left[i] || match(left[i])) {
left[i] = u;
return 1;
}
}
return 0;
}
bool judge(int mid) {
for (int i=1; i<=m; i++) {
for (int j=1; j<=n+1; j++) {
g[i][j] = 1;
if (j>1 && abs(b[i]-a[j-1])>mid) g[i][j] = 0;
if (jmid) g[i][j] = 0;
}
}
int ans = 0;
for (int i=1; i<=n+1; i++) left[i] = 0;
for (int i=2; i<=n; i++) {
if (abs(a[i-1]-a[i])>mid) {
for (int j=1; j<=m; j++) vis[j] = 0;
if (!match(i)) return 0;
ans++;
}
}
for (int i=1; i<=n+1; i++) {
if (i==1 || i==n+1 || abs(a[i-1]-a[i])<=mid) {
for (int j=1; j<=m; j++) vis[j] = 0;
ans += match(i);
}
}
return ans == m;
}
int main(){
int T;
scanf("%d",&T);
while (T--){
scanf("%d%d",&n,&m);
for (int i=1; i<=n; i++) scanf("%d",&a[i]);
for (int j=1; j<=m; j++) scanf("%d",&b[j]);
int left = 0, right = INF;
int mid, ans = 0;
while (left <= right) {
mid = (left+right)>>1;
if (judge(mid)) {
right = mid-1;
ans = mid;
}
else left = mid+1;
}
printf("%d\n",ans);
}
return 0;
}
K:待填坑
L:这题卡了N久,最后还没写出来,太菜了。。。据说出题人搞错了,数据当成连续子串也A了。。。
emmm,正解DP我还没想出来,平时练习DP太少了。。
先放上一个有毛病的AC代码,当成连续子串处理的。
#include
using namespace std;
typedef long long LL;
const int maxn = 1e5+10;
int a[maxn];
LL sum[maxn];
int n,k;
inline int Max(int x, int y) {return x>y?x:y; }
int main(){
while (scanf("%d%d",&n,&k) == 2) {
for (int i=1; i<=n; i++) {
scanf("%d",&a[i]);
a[i] %= k;
}
sum[0] = 0;
for (int i=1; i<=n; i++) sum[i] = sum[i-1] + a[i];
int mx = -1;
for (int i=1; i<=n; i++) {
for (int j=n; j>=i; j--) if ((sum[j]-sum[i-1])%k == 0) {
mx = Max(mx,j-i+1);
break;
}
}
printf("%d\n",mx);
}
return 0;
}