今天我们组出题,我的题数据出水了,以后出数据一定要想想暴力能否cao过去,不然很尴尬,要背锅的啊!QwQ
今天的写题任务没有完成。下午和晚上的效率都很低,因为寝室没人路上浪费半小时,调题也很慢,晚饭边吃边玩手机,这些坏习惯必须改。特别是不准无意中看手机,消息一条条回,涵涵的消息有特别提醒一般也不会错过。总之不能时不时就看一下手机。静下心来!认真深入的想题!
DP题,其他题一定要想清楚再写。写出ds题未必代码能力强,现在应该多练细节多的DP,各种代码不太套路,需要自己思考的题。推清楚细节再写,尽量一次AC,必须做到!
明天又要打比赛,一定要以平和谦虚的姿态来应对。认真看题,仔细思考,随时思维活跃!多想,想清楚再做,但有大胆敢于尝试,说不定就可以水过去,但是这一切都高效完成,其实根本花不了太多时间。
看到自己水平还和很多厉害的学长有很大差距,所以静下心来练题,提高自己,特别是多练自己的思维,和写题时推细节的能力。
今天的题还没有写,明天调完题应该抽时间写了。
A: 给一个点集,找一条直线使得所有点到这条直线的带权距离和最小。(并且所有点在该直线同侧)。求一个凸包,利用物理性质,该直线一定为凸包的一条边(否则凸包会倒),转换为重心到每条边的距离最小值。
B:数位DP:求[L,R]区间内有多少个数的奇数位和与偶数位和的最大公约数小于等于k。
直接记录奇数位的和和偶数位的和,暴力dp
T特别大,有个技巧,把k相同的放在一起,记忆化搜索(记录最大公约数为k,好像不用),因为顶上界的状态很少(只有18种),所一有很多重复状态。
时间复杂度O(18 * 10 81 *81 + T 18 * 10 * 81)
很巧妙的将k分类和不顶上界时记忆化(顶上界时各情况是不同的,不能记忆化!)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
ll L,R;
int id;
node () { L = R = 0; }
node(ll x,ll y,int t):L(x),R(y),id(t){};
};
ll f[20][100][100][2];
int vis[20][100][100][2];
int T,k,a[20],tot,gcd[100][100],curk,dfstime;
ll L,R,ans[20000];
vector <node> vec[100];
int GCD(int x,int y){
if ( !y ) return x;
return GCD(y,x % y);
}
void init(){
for (int i = 1 ; i <= 90 ; i++)
for (int j = 1 ; j <= 90 ; j++)
gcd[i][j] = GCD(i,j);
}
void pre(ll x,int a[],int &tot){
tot = 0;
while ( x ){
a[++tot] = (int)(x % 10);
x /= 10;
}
}
ll DP(int x,int sum1,int sum2,int t){
if ( !x ){
if ( sum1 && sum2 && gcd[sum1][sum2] <= curk ) return 1;
return 0;
}
//不顶上界时情况相同,记忆化搜索
if ( !t && vis[x][sum1][sum2][t] == dfstime ) return f[x][sum1][sum2][t];
vis[x][sum1][sum2][t] = dfstime;
ll &res = f[x][sum1][sum2][t] = 0;
if ( t ){
if ( x & 1 ){
for (int i = 0 ; i < a[x] ; i++)
res += DP(x - 1,sum1 + i,sum2,0);
res += DP(x - 1,sum1 + a[x],sum2,1);
}
else{
for (int i = 0 ; i < a[x] ; i++)
res += DP(x - 1,sum1,sum2 + i,0);
res += DP(x - 1,sum1,sum2 + a[x],1);
}
}
else{
for (int i = 0 ; i <= 9 ; i++){
if ( x & 1 ) res += DP(x - 1,sum1 + i,sum2,0);
else res += DP(x - 1,sum1,sum2 + i,0);
}
}
return res;
}
ll calc(ll x){
pre(x,a,tot);
return DP(tot,0,0,1);
}
int main(){
freopen("input.txt","r",stdin);
init();
scanf("%d",&T);
for (int t = 1 ; t <= T ; t++){
scanf("%d %lld %lld",&k,&L,&R); k = min(k,90);
vec[k].push_back((node){L,R,t});
}
for (int t = 1 ; t <= 90 ; t++){
++dfstime; curk = t;
for (int i = 0 ; i < vec[t].size() ; i++){
L = vec[t][i].L , R = vec[t][i].R;
ans[vec[t][i].id] = calc(R) - calc(L - 1);
}
}
for (int t = 1 ; t <= T ; t++) printf("%lld\n",ans[t]);
return 0;
}
C:(我出的有锅的题)bzoj4398无向图求1号点出发的最短回路。
可以二进制分组+spfa,还有神奇的重构图hzwer的题解
还可以更暴力直接用最短路树上删除最后一点边求最短路的知识更新,链剖维护一下(也可以排序后用并查集)
造数据要能卡掉暴力和贪心(1号点度数加大,调整边权),还要注意判重边和自环,无向边判重要把(x,y),(y,x)都加入set
D:高级的线性基,看似博弈,其实利用xor两次撤销的知识,在当前不能决策留给后面撤销,好题!
大概是对的,很好写
#include<bits/stdc++.h>
using namespace std;
#define maxn 10020
typedef long long ll;
const int mx = 4;
struct Matirx{
ll a[64];
void init(){
memset(a,0,sizeof(a));
}
void insert(ll x){
for (int i = mx ; i >= 0 ; i--){
if ( (a[i] >> i) & 1 ){
if ( (x >> i) & 1 ) x ^= a[i];
}
else{
if ( (x >> i) & 1 ){ a[i] = x; break; }
}
}
}
int query(int i){
return (a[i] >> i) & 1;
}
}base1,base2;
int T,n,m;
ll a[maxn],b[maxn],c[maxn],d[maxn],cur;
int main(){
freopen("input.txt","r",stdin);
scanf("%d",&T);
while ( T-- ){
cur = 0 , base1.init() , base2.init();
scanf("%d %d",&n,&m);
for (int i = 1 ; i <= n ; i++) scanf("%lld %lld",&a[i],&b[i]) , cur ^= a[i] , base1.insert(a[i] ^ b[i]);
for (int i = 1 ; i <= m ; i++) scanf("%lld %lld",&c[i],&d[i]) , cur ^= c[i] , base2.insert(c[i] ^ d[i]);
for (int i = mx ; i >= 0 ; i--){
int t = (cur >> i) & 1,x = base1.query(i) , y = base2.query(i);
if ( x && y ){ //都能操作Alice选择
cur ^= base1.a[i] ^ base2.a[i];
base1.insert(base1.a[i] ^ base2.a[i]);
}
else if ( x ){ //Alice能操作
if ( !t ) cur ^= base1.a[i];
}
else if ( y ){ //Bob能操作
if ( t ) cur ^= base2.a[i];
}
//都不能操作cur不变
}
cout<<cur<<endl;
}
return 0;
}
H:很难的博弈,没搞懂,明天去问!
总之,现在我的水平还很低,不要停留于过去的“辉煌”。静心!努力!坚持到最后一刻!
明天比赛目标过4-6题,rank前5,加油!