Solutions
A. There Are Two Types Of Burgers
题意:
做一个(A)需要两个(b)和两个(p),能卖(h)元;做一个(B)需要两个(b)和两个(f),能卖(c)元。给出(b,p,f)的数量,求最多卖多少元。
思路:
比赛的时候用循环搞了,判断(h,c)的大小关系,决定先做什么。也可以(b=b/2),然后判断大小,每次取最小值,利润直接算,然后更新(b),再进行一次。
//#define DEBUG
#include<bits/stdc++.h>
using namespace std;
#define lson (rt<<1)
#define rson (rt<<1|1)
const int N=100010;
const int inf=0X3f3f3f3f;
const long long INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = acos(-1.0);
const int mod = 1000000007;
typedef long long ll;
int main() {
#ifdef DEBUG
freopen("in.txt","r",stdin);
#endif
int _,b,p,f;
double h,c;
ll ans;
for(scanf("%d",&_);_;_--) {
scanf("%d%d%d%lf%lf",&b,&p,&f,&h,&c);
ans=0;
if(h>c) {
while(b>=2&&p) {
ans+=h;
b-=2;
p--;
}
while(b>=2&&f) {
ans+=c;
b-=2;
f--;
}
} if(h<c) {
while(b>=2&&f) {
ans+=c;
b-=2;
f--;
}
while(b>=2&&p) {
ans+=h;
b-=2;
p--;
}
} else {
int zhi=p+f;
while(b>=2&&zhi) {
ans+=h;
b-=2;
zhi--;
}
}
printf("%lld
",ans);
}
}
//#define DEBUG
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
const int inf=0X3f3f3f3f;
const long long INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = acos(-1.0);
const int mod = 1000000007;
typedef long long ll;
int _;
int b,p,f;
int h,c;
int main() {
#ifdef DEBUG
freopen("in.txt","r",stdin);
#endif
for (scanf("%d",&_);_;_--) {
scanf("%d%d%d%d%d",&b,&p,&f,&h,&c);
ll ans=0;
b/=2;
if (h>c) {
int x=min(b,p);
ans+=x*h;
b-=x,p-=x;
int y=min(b,f);
ans+=y*c;
} else {
int x=min(b,f);
ans+=x*c;
b-=x,f-=x;
int y=min(b,p);
ans+=y*h;
}
printf("%lld
",ans);
}
}
B. Square Filling
题意:
给出一个(01)矩阵(A),让你用一个全(0)矩阵(B),通过每次选(2 imes2)的子矩阵设值为(1),把(B)变为(A),可以的话,输出你选的子矩阵的左上角坐标。
思路:
范围不大,直接枚举(1)的位置,判断周围是否存在全(1)子矩阵。
题解思路是存在子矩阵乘积大于0的,就全部设置为(2),然后一直进行,如果最后还有(1),说明不行。
#include <bits/stdc++.h>
#define lowbit(x) (x)&(-x)
#define srand() srand(time(0))
#define pi acos(-1.0)
#define printftime() printf("Time used = %.2f
",(double)clock()/CLOCKS_PER_SEC)
using namespace std;
typedef long long ll;
int a[100][100];
int flag[100][100];
struct len {
int l,r;
}ans[100000];
int main()
{
int n,m,cnt=1;int f=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&a[i][j]);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]){
if(a[i-1][j-1]&&a[i-1][j]&&a[i][j-1]){
ans[cnt].l=i-1;
ans[cnt++].r=j-1;
continue ;
}
if(a[i][j-1]&&a[i+1][j]&&a[i+1][j-1]){
ans[cnt].l=i;
ans[cnt++].r=j-1;
continue ;
}
if(a[i+1][j+1]&&a[i+1][j]&&a[i][j+1]){
ans[cnt].l=i;
ans[cnt++].r=j;
continue ;
}
if(a[i-1][j]&&a[i-1][j+1]&&a[i][j+1]){
ans[cnt].l=i-1;
ans[cnt++].r=j;
continue ;
}
f=1;
}
}
}
if(f)puts("-1");
else {
printf("%d
",cnt-1);
for(int i=1;i<cnt;i++)printf("%d %d
",ans[i].l,ans[i].r);
}
}
//#define DEBUG
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
const int inf=0X3f3f3f3f;
const long long INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = acos(-1.0);
const int mod = 1000000007;
typedef long long ll;
int n, m;
int a[100][100];
int main() {
#ifdef DEBUG
freopen("in.txt","r",stdin);
#endif
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++)
scanf("%d", &a[i][j]);
}
vector<pair<int, int> > ans;
for (int i = 1; i < n; i++) {
for (int j = 1; j < m; j++) {
if (a[i][j] * a[i][j + 1] * a[i + 1][j] * a[i + 1][j + 1] > 0 ) {
a[i][j] = a[i][j + 1] = a[i + 1][j] = a[i + 1][j + 1] = 2;
ans.push_back({i, j});
}
}
}
bool ok=true;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (a[i][j] == 1) {
ok = false; break;
}
}
}
if (!ok) puts("-1");
else {
printf("%d
", (int)ans.size());
for (int i = 0; i < (int)ans.size(); i++) {
printf("%d %d
", ans[i].first, ans[i].second);
}
}
return 0;
}
C. Gas Pipeline
题意:
给一条公路用(01)字符串表示,有十字路口用(1)表示,现在要架管道,十字路口的时候,管道必须在高度为(2)的位置,其他位置高度可以为(1),管道同时需要支架,现给出(01)字符串,让你给公路架管道,保证开始和结束都是高度为(1)的管道。给出单位长度管道的花费和单位高度支架的花费,求架完公路的最小花费。
思路:
很容易想到贪心,处理出连续(0)序列的长度,(0)的位置可能不下降,所以判断一下下降与不下降的花费,选择较小的。
(dalao)好像都是动态规划写的。(dp[i][0/1])表示(i)位置右边支架为(0/1)的最小花费,转移的话就,
当(s[i]=1)的时候,右边支架高度只能为2,所以(dp[i][0]=INF),并且只能由(d[i-1][1])转移得到,因为左边支架高度也只能为(2)。初始(dp[0][0]=b,dp[0][1]=INF),因为左边由高度为(1)开始的。答案即为(dp[n][0])。
//#define DEBUG
#include<bits/stdc++.h>
using namespace std;
#define lson (rt<<1)
#define rson (rt<<1|1)
const int N=100010;
const int inf=0X3f3f3f3f;
const long long INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = acos(-1.0);
const int mod = 1000000007;
typedef long long ll;
char s[2*N];
ll d[2*N];
int main() {
#ifdef DEBUG
freopen("in.txt","r",stdin);
#endif
int _,len;
ll a,b;
for(scanf("%d",&_);_;_--) {
scanf("%d%lld%lld",&len,&a,&b);
scanf("%s",s+1);
d[len+1]=0;
for(int i=len;i>=1;i--) {
if(s[i]=='1') d[i]=0;
else d[i]=d[i+1]+1;
}
//for(int i=1;i<=len;i++) printf("%d",d[i]);
int op=0; //下降态
ll sum=0;
ll cnt=0; // 支柱:0但不下降
for(int i=1;i<=len;i++) {
if(s[i]=='0') {
if(op) {
if(2*a-d[i]*b+b<=0||i+d[i]-1==len) { //下降
if(i+d[i]-1==len) { //最后下
sum+=(d[i]+2)*a;
cnt+=2*b;
cnt+=d[i]*b;
} else { //中间下
sum+=(d[i]+1)*a;
cnt+=(d[i]-1)*b;
cnt+=2*b;
}
op=!op;
} else { // 不下降
sum+=d[i]*a;
cnt+=d[i]*2*b;
}
} else {
if(i+d[i]-1!=len) {
sum+=(d[i]-1)*a;
cnt+=d[i]*b;
} else {
sum+=d[i]*a;
cnt+=(d[i]+1)*b;
}
}
i=i+d[i]-1;
} else {
if(op) {
sum+=a;
} else {
sum+=2*a;
op=!op;
}
cnt+=2*b;
}
//printf("i=%d %lld **** %lld
",i,sum,cnt);
}
sum=sum+cnt;
printf("%lld
",sum);
}
}
//#define DEBUG
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
const int inf = 0X3f3f3f3f;
const long long INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = acos(-1.0);
const int mod = 1000000007;
typedef long long ll;
char s[2*N];
ll dp[2*N][2];
int _;
int n;
ll a, b;
int main() {
#ifdef DEBUG
freopen("in.txt", "r", stdin);
#endif
for (scanf("%d", &_); _; _--) {
scanf("%d %lld %lld", &n, &a, &b);
scanf("%s", s+1);
dp[0][0] = b; dp[0][1] = INF;
for (int i = 1; i <= n; i++) {
if (s[i] == '0') {
dp[i][1] = min(dp[i - 1][1] + a + 2 * b, dp[i - 1][0] + 2 * a + 2 * b);
dp[i][0] = min(dp[i - 1][1] + 2 * a + b, dp[i - 1][0] + a + b);
} else {
dp[i][0] = INF;
dp[i][1] = dp[i - 1][1] + a + 2 * b;
}
}
printf("%lld
", dp[n][0]);
}
return 0;
}
D. Number Of Permutations
题意:
给出(n)个有序对((x_i,y_i)),如果一组有序对,按(x_i)排序非递减或按(y_i)排序非递减的话定义为坏的。然后问(n)的全排列生成的每组有序对有多少个好的。比如(n=3),给出((1,2),(3,2),(3,1)),那么按全排列生成的即为:
(123 :(1,2),(3,2),(3,1));
(132:(1,3),(3,1),(3,2));
(vdots)
思路:
逆向思维,一共有(n!)种结果,定义(cnt_1)为按(x_i)排序非递减的,定义(cnt_2)为按(y_i)排序非递减的,定义(cnt_{12})为(x_i和y_i)同时非递减的。那么答案就是(n!-cnt_1-cnt_2+cnt_{12})。
(cnt_1)的求法:假设这么一个序列:(1,2,1,3),全排列后只有两个非递减的,即(2!)。再比如:(1,2,3,2,1),全排列后有(2! {ast} 2!)个非递减的。因为(1、2)重复。所以(cnt_1)就出来了。(cnt_2)同理。
(cnt_{12})的求法:我们可以先按(x_i)排序再按(y_i)排序,同样也是统计重复的个数。但最后要检查是否满足(y_i)非递减。
//#define DEBUG
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
const int inf = 0X3f3f3f3f;
const long long INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = acos(-1.0);
const int mod = 998244353;
typedef long long ll;
pair<int, int> d[3 * N];
map<int, int> a, b;
map<pair<int, int>, int> ab;
int n;
int fac[3 * N];
int main() {
#ifdef DEBUG
freopen("in.txt", "r", stdin);
#endif
scanf("%d", &n);
fac[0] = 1;
for (int i = 1; i <= n; i++) {
fac[i] = 1ll * fac[i - 1] * i % mod;
scanf("%d %d", &d[i].first, &d[i].second);
a[d[i].first]++; b[d[i].second]++;
ab[d[i]]++;
}
sort(d + 1, d + n + 1);
int sum = fac[n];
int temp = 1;
for (auto i : a) {
temp = 1ll * temp * fac[i.second] % mod;
}
sum = (sum - temp + mod) % mod;
temp = 1;
for (auto i : b) {
temp = 1ll * temp * fac[i.second] % mod;
}
sum = (sum - temp + mod) % mod;
bool ok = true;
temp = 1;
for (auto i : ab) {
temp = 1ll * temp * fac[i.second] % mod;
}
for (int i = 1; i < n; i++) {
if(d[i].second > d[i + 1].second) {
ok = false; break;
}
}
if(ok) sum = (sum + temp) % mod;
printf("%d
", sum);
}
E. XOR Guessing
题意:
猜数字(w),你每次询问(100)个数,会给你一个(w)与其中一个的异或结果(x),再次询问(100)个数,又给你一个(w)与其中一个的异或结果(y),最多询问两次,且你询问的所有数字不能重复,求(w)。
思路:
很神奇的思路,(w)范围最多(14)位二进制,我们可以先用(100)个低(7)的数字询问,那么(x)的高(7)位就是(w)的高(7)位,再用高(7)位的数字询问,那么(y)的低(7)位就是(w)的低(7)位。(1sim100)刚好能用低(7)位表示,然后可以把(1{sim}100)的数字左移(7)位,就生成高(7)位的数字了。
//#define DEBUG
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
const int inf = 0X3f3f3f3f;
const long long INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = acos(-1.0);
const int mod = 1000000007;
typedef long long ll;
int main() {
#ifdef DEBUG
freopen("in.txt", "r", stdin);
#endif
printf("?");
for (int i = 0; i < 100; i++) printf(" %d", i + 1);
puts("");
fflush(stdout);
int x;
scanf("%d", &x);
printf("?");
for (int i = 0; i < 100; i++) printf(" %d", i + 1 << 7);
puts("");
fflush(stdout);
int y;
scanf("%d", &y);
printf("! %d", (x & ~0x7f) | (y & 0x7f));
}
F. Remainder Problem
题意:
给出(a_1,a_2,{dots},a_{500000}),且全为(0),然后有(q)次询问,
- 1 (x y) :(a_x + y)
- 2 (x y):(sum_{i{in}R(x,y)}a_i),(R(x,y))是(1{sim}500000)的下标(i\%x=y)的集合
思路:
看题解是根号分治,题目大多是(q)和(N)同一数量级 ,每次修改在原数组上修改,同时用数组预处理出小于(sqrt(N))的查询(O(sqrt(N))),大于(sqrt(N))的查询就累加原数组的值(O({frac{N}{X}})),其中(X>{sqrt(N)}),所以总复杂度(O(N{sqrt(N)}))。
见代码
//#define DEBUG
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
const int inf = 0X3f3f3f3f;
const long long INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = acos(-1.0);
const int mod = 1000000007;
typedef long long ll;
int q;
int a[5*N];
int d[710][710];
int main() {
#ifdef DEBUG
freopen("in.txt", "r", stdin);
#endif
scanf("%d", &q);
int op, x, y;
for (int i = 1; i <= q; i++) {
scanf("%d %d %d", &op, &x, &y);
if (op == 1) {
a[x] += y;
for (int j = 1; j < 710; j++) {
d[j][x % j] += y; //d[j][模j的余数]
}
} else {
int ans = 0;
if (x < 710) ans = d[x][y]; // d[x][模x的余数=y]
else {
for (int j = y; j <= 500000; j += x) {
ans += a[j];
}
}
printf("%d
", ans);
}
}
}