今天又只過了一題,很差!!!
E題應該能想出來的,構造題多找性質,發現很強的性質後構造就很方面了。
看題要有舍有得,有些題顯然很難就沒必要看了。把注意力放在有人做的可做題上,靜下心來深入思考很重要。
如果沒有別的題可做,1道題想一小時很正常。多想別的做法,甚至亂搞,但是肯定不能過的做法別多糾結。膽大嘗試做法,但過不了果斷放棄,不要浪費太多時間。
大膽利用性質猜結論!
調題應該更快,敢於問。注意細節錯誤!靜下心來用眼讀代碼,邊讀邊思考,減少對拍,因爲考場上沒法也沒時間對拍!!!
題解:
A:求多項式的商。巧妙推式子。
主要是推式子很巧,很好寫!
#include<bits/stdc++.h>
using namespace std;
#define maxn 5020
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
typedef long long ll;
const ll mod = 1e9 + 7;
ll a[maxn],b[maxn],c[maxn],ans,mx;
int m;
inline ll power(ll x,ll y){
ll res = 1;
while ( y ){
if ( y & 1 ) res = res * x % mod;
x = x * x % mod;
y >>= 1;
}
return (res + mod) % mod;
}
void cal_C(){
rep(i,1,m){
ll mul = 1,x = 1,cur = 0;
rep(j,1,m) if ( j != i ) mul = mul * (a[j] - a[i]) % mod;
mul = power(mul,mod - 2);
rep(j,0,m - 2) cur = (cur + x * b[j]) % mod , x = x * (-a[i]) % mod;
c[i] = (cur * mul % mod + mod) % mod;
}
//rep(i,1,m) c[i] = (c[i] + c[i - 1]) % mod;
}
void solve(){
rep(i,1,mx){
ll cur = 0;
rep(j,1,m){
if ( a[j] < i ) cur = (cur + c[j]) % mod;
}
ans = (ans + cur * power(i,mod - 2)) % mod;
}
ans = (ans % mod + mod) % mod;
printf("%lld\n",ans);
}
int main(){
freopen("input.txt","r",stdin);
while ( ~scanf("%d",&m) ){
mx = ans = 0;
rep(i,1,m) scanf("%lld",&a[i]) , mx = max(mx,a[i]);
rep(i,0,m - 2) scanf("%lld",&b[i]);
cal_C();
solve();
}
return 0;
}
B:巧妙的貪心,利用每個聯通塊必選一個點,其餘點從小到大選。大膽推性質,想結論!
C:N*N矩陣,每行每列填一個數,使兩兩連線不同。
用原根構造(g^(1 - n-1)恰好爲1- p-1).因爲保證n +1爲質數,所以大膽猜想與原根有關。
填(i,g^i % (n + 1))
D:求對於每個前綴i,找一個分界點j,xorsum(1,j) + xorsum(j +1,i)最大。
每一位,出現奇數次爲0(因爲無論怎麼選都貢獻1),偶數次爲1(想選到奇數次分開,就貢獻2)
相當於查詢x在pre中&的最大值。
F[1<<10][1<<10]的分塊過不了
考慮直接對一個pre的所有子集進行更新,查詢時只需知道當前要填的數是否被包含,就可以唯一確定,非常巧妙!
O(nlogn)
注意輸出優化要特判負數和0
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
#define maxn (1 << 22)
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define inf 1e8
int a[maxn],ans[maxn],n;
int q[maxn],hh,tt,dfstime,vis[maxn];
inline int read(){
register int num = 0;
register char ch = getchar();
while ( ch > '9' || ch < '0' ) ch = getchar();
while ( ch <= '9' && ch >= '0' ) num = num * 10 + ch - '0' , ch = getchar();
return num;
}
int num[10];
inline void write(int x){
register int cnt = 0;
if ( !x ){ printf("0"); return; }
while ( x ) num[++cnt] = x % 10 , x /= 10;
while ( cnt ) putchar(num[cnt--] + '0');
}
inline void insert(int x){
if ( vis[x] == dfstime ) return;
tt = hh = 0; q[tt++] = x , vis[x] = dfstime;
while ( hh < tt ){
int x = q[hh++];
if ( !x ) continue;
rep(i,0,19){
if ( (x >> i) & 1 ){
if ( vis[x ^ (1 << i)] != dfstime ){
vis[x ^ (1 << i)] = dfstime;
q[tt++] = x ^ (1 << i);
}
}
}
}
}
inline int query(int x){
int cur = 0;
repd(i,19,0){
if ( x & (1 << i) ){
if ( vis[cur | (1 << i)] == dfstime ) cur |= 1 << i;
}
}
return cur;
}
int main(){
freopen("input.txt","r",stdin);
// freopen("1.out","w",stdout);
while ( ~scanf("%d",&n) ){
++dfstime;
int pre = 0,cur = 0,S = (1 << 20) - 1;
rep(i,1,n){
a[i] = read() , pre ^= a[i] , cur = pre ^ S;
insert(pre);
ans[i] = query(cur) * 2 + pre;
}
rep(i,1,n){
write(ans[i]);
// if ( i < n ) putchar(' ');
// else putchar(10);
if ( i < n ) printf(" ");
else printf("\n");
}
}
return 0;
}
E:給出後綴排序後第i位的位置,構造一個0,1的可行解。
每次找到最後一個位置的排名,如果在第一則填0刪去,不影響其他點排名。如果不在第一位則必須填1。並且它之前全部爲0,之後全部爲1。再一次後綴數組判斷是否可行。
注意後綴數組有些地方要倒着for(位置靠後字典序更小)
還要一種很巧的判定方法。
rk[sa[i] +1] > rk[sa[i +1] +1]則所需字符集+1,使用於字符集更大的情況
#include<bits/stdc++.h>
using namespace std;
#define maxn 100020
#define rep(i,l,r) for (register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
int a[maxn];
int s[maxn],c[maxn],t1[maxn * 2],t2[maxn * 2],sa[maxn];
int n;
//sa[i]表示排名爲i的後綴的位置
//rk[i]表示第i個後綴的排名
//x[i]表示i的排名(第一關鍵字)
//y[i]表示第二關鍵字排名爲i的後綴的起始位置
//h[i]表示後綴i在排序後與前一位的lcp
//求i,j的lcp是排序後rk[i],rk[j],height的min
void suffix_array(){
int m = 1 , *x = t1 , *y = t2;
rep(i,0,m) c[i] = 0;
rep(i,0,n - 1) c[x[i] = s[i]]++;
rep(i,1,m) c[i] += c[i - 1];
rep(i,0,n - 1) sa[--c[x[i]]] = i;
// rep(i,1,n) cout<<sa[i - 1]<<" ";
// cout<<endl;;
for (register int k = 1 ; k < n ; k <<= 1){
register int p = 0;
memset(y,0,sizeof(t1));
repd(i,n - 1,n - k) y[p++] = i; //必須倒着for,在後面的位置更小
rep(i,0,n - 1) if ( sa[i] >= k ) y[p++] = sa[i] - k;
rep(i,0,m) c[i] = 0;
rep(i,0,n - 1) c[x[y[i]]]++;
rep(i,1,m) c[i] += c[i - 1];
repd(i,n - 1,0) sa[--c[x[y[i]]]] = y[i];
p = 0 , swap(x,y) , x[sa[0]] = ++p;
rep(i,1,n - 1) x[sa[i]] = (y[sa[i]] == y[sa[i - 1]]) && (y[sa[i] + k] == y[sa[i - 1] + k]) ? p : ++p;
if ( p >= n ) break; //如果當前已經完成排名,則break
m = p;
}
}
bool check(){
// rep(i,1,n) cout<<sa[i - 1]<<" ";
// cout<<endl;;
rep(i,1,n) if ( a[i] != sa[i - 1] + 1 ) return 0;
return 1;
}
int main(){
freopen("input.txt","r",stdin);
while ( ~scanf("%d",&n) ){
rep(i,1,n) scanf("%d",&a[i]);
int id = 1;
while ( a[id] == n - id + 1 ) id++;
if ( id >= n ){ printf("YES\n"); continue; }
rep(i,id,n) if ( a[i] == n - id + 1){ id = i; break; }
rep(i,1,id - 1) s[a[i] - 1] = 0;
rep(i,id,n) s[a[i] - 1] = 1;
suffix_array();
if ( check() ) printf("YES\n");
else printf("NO\n");
}
return 0;
}
F:特技分塊,好題
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
#define maxn 200020
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define inf 1e8
typedef long long ll;
inline int read(){
register int num = 0;
register char ch = getchar();
while ( ch > '9' || ch < '0' ) ch = getchar();
while ( ch <= '9' && ch >= '0' ) num = num * 10 + ch - '0' , ch = getchar();
return num;
}
int num[10];
inline void write(int x){
register int cnt = 0;
if ( !x ){ printf("0"); return; } //Ò»¶šÒªÌØÅÐ0£¡£¡£¡
while ( x ) num[++cnt] = x % 10 , x /= 10;
while ( cnt ) putchar(num[cnt--] + '0');
}
struct node{
int x,y;
}dt[maxn];
int n,m,q,deg[maxn],sz,tag[maxn],id[maxn],tot,exi[maxn];
ll v[maxn],w[2][1020][1020];
int big[maxn],rev[maxn];
vector <int> vec[maxn];
void init(){
rep(i,1,n) tag[i] = deg[i] = id[i] = 0 , vec[i].clear();
rep(i,1,n) v[i] = (ll)rand() * rand() * rand();
rep(i,0,m / sz) rev[i] = 0;
rep(i,0,m) exi[i] = 1;
memset(w,0,sizeof(w));
tot = 0;
}
inline void update(int i,int cur){
int x = dt[i].x , y = dt[i].y;
if ( tag[x] ){
w[0][cur][id[x]] ^= v[y];
w[1][cur][id[x]] ^= v[y];
}
if ( tag[y] ){
w[0][cur][id[y]] ^= v[x];
w[1][cur][id[y]] ^= v[x];
}
}
inline void modify(int l,int r){
int L = l == 0 ? 0 : ((l - 1) / sz + 1),R = (r + 1) / sz - 1;
rep(i,L,R){
rev[i] ^= 1;
}
if ( R >= L ){
rep(i,l,sz * L - 1) exi[i] ^= 1 , update(i,i / sz);
rep(i,(R + 1) * sz,r) exi[i] ^= 1 , update(i,i / sz);
}
else{
//ÖЌ䲻°üº¬ÈÎÒâÒ»¿éÒªÌØÅÐ
rep(i,l,r) exi[i] ^= 1 , update(i,i / sz);
}
}
inline ll cal(int id,int x){
if ( exi[id] ^ rev[id / sz] ){
if ( dt[id].x == x ) return v[dt[id].y];
return v[dt[id].x];
}
return 0;
}
ll query(int x){
ll res = 0;
if ( tag[x] ){
rep(i,0,m / sz){
res ^= w[rev[i]][i][id[x]];
}
}
else{
for (register int i = 0 ; i < vec[x].size() ; i++){
res ^= cal(vec[x][i],x);
}
}
return res;
}
int main(){
freopen("input.txt","r",stdin);
while ( ~scanf("%d %d",&n,&m) ){
sz = sqrt(m * 2);
init();
rep(i,0,m - 1){
dt[i].x = read() , dt[i].y = read();
deg[dt[i].x]++ , deg[dt[i].y]++;
vec[dt[i].x].push_back((int)i) , vec[dt[i].y].push_back((int)i);
}
rep(i,1,n) if ( deg[i] > sz ) tag[i] = 1 , big[++tot] = i , id[i] = tot;;
rep(i,0,m / sz){
rep(j,i * sz,min(m - 1,(i + 1) * sz - 1)){
int x = dt[i].x,y = dt[i].y;
if ( tag[x] ) w[0][i][id[x]] ^= v[y];
if ( tag[y] ) w[0][i][id[y]] ^= v[x];
}
}
q = read();
while ( q-- ){
int tp,x,y;
tp = read() , x = read() , y = read();
if ( tp == 1 ){
modify(x - 1,y - 1);
}
else{
if ( query(x) == query(y) ) printf("1");
else printf("0");
}
}
printf("\n");
}
return 0;
}
G:NTT優化數位DP
#include<bits/stdc++.h>
using namespace std;
#define maxn 100020
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define inf 1e8
inline int read(){
register int num = 0;
register char ch = getchar();
while ( ch > '9' || ch < '0' ) ch = getchar();
while ( ch <= '9' && ch >= '0' ) num = num * 10 + ch - '0' , ch = getchar();
return num;
}
int num[10];
inline void write(int x){
register int cnt = 0;
if ( !x ){ printf("0"); return; } //Ò»¶šÒªÌØÅÐ0£¡£¡£¡
while ( x ) num[++cnt] = x % 10 , x /= 10;
while ( cnt ) putchar(num[cnt--] + '0');
}
typedef long long ll;
const ll p = 998244353,g = 3;
const int len = 32768,cnt = 15,mod = 10857;
ll f[32][maxn],c[maxn],res[maxn],inv;
int n,rev[maxn];
int a[6] = {2,3,5,7,11,47},t[5] = {1,2,3,5,7};
inline ll power(ll x,ll y,ll p){
ll res = 1;
while ( y ){
if ( y & 1 ) res = res * x % p;
x = x * x % p;
y >>= 1;
}
return res;
}
void NTT(ll a[],int tag){
rep(i,0,len - 1) if ( rev[i] > i ) swap(a[rev[i]],a[i]);
for (register int i = 1 ; i < len ; i <<= 1){
ll wn = power(g,(p - 1) / (i << 1),p);
for (register int j = 0 ; j < len ; j += (i << 1)){
ll w = 1;
for (register int k = 0 ; k < i ; k++){
ll x = a[j + k] , y = a[i + j + k] * w % p;
a[j + k] = (x + y) % p;
a[i + j + k] = (x - y + p) % p;
w = w * wn % p;
}
}
}
if ( tag == -1 ){
reverse(a + 1,a + len);
rep(i,0,len - 1) a[i] = inv * a[i] % p;
}
}
void qpow(ll a[],ll b[],ll n){
rep(i,0,len - 1) c[i] = 0;
rep(i,0,len - 1) c[n * i % mod] = (c[n * i % mod] + a[i]) % p;
NTT(c,1);
rep(i,0,len - 1) c[i] = c[i] * b[i] % p;
NTT(c,-1);
rep(i,0,len - 1) a[i] = 0;
rep(i,0,len - 1) a[i % mod] = (a[i % mod] + c[i]) % p;
}
void init(){
inv = power(len,p - 2,p);
rep(i,0,len - 1){
int cur = 0;
rep(j,0,cnt - 1){
if ( i & (1 << j) ) cur += 1 << (cnt - j - 1);
}
rev[i] = cur;
}
rep(i,0,4) f[0][t[i]] = 1;
rep(i,1,29){
memcpy(f[i],f[i - 1],sizeof(f[i])) , NTT(f[i - 1],1);
qpow(f[i],f[i - 1],power(10,1 << (i - 1),mod));
}
NTT(f[29],1);
}
int check(int x){
rep(i,0,5) if ( (x % a[i]) == 0 ) return 0;
return 1;
}
int main(){
// freopen("input.txt","r",stdin);
init();
while ( ~scanf("%d",&n) ){
n--;
memset(res,0,sizeof(res));
res[0] = 1;
repd(i,29,0){
if ( n & (1 << i) ) qpow(res,f[i],power(10,1 << i,mod));
}
ll ans = 0;
// rep(i,0,10) cout<<res[i]<<" ";
// cout<<endl;
rep(i,0,mod - 1){
int cnt = 0;
rep(j,0,4) if ( check(i * 10 + t[j]) ) cnt++;
ans = (ans + res[i] * cnt) % p;
}
printf("%lld\n",ans);
}
return 0;
}
H:用圓的包含關係建樹,然後DP,明天寫
明天目標過3題,進入前5名!提高思維速度,減少代碼錯誤和罰時,靜心深入思考!!!
明天早點睡!一刻不能放鬆!先調完題才能回寢室!